{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# \u7b2c\u5341\u4e00\u7ae0\uff1a\u7f51\u7edc\u4e0eWeb\u7f16\u7a0b\n \u672c\u7ae0\u662f\u5173\u4e8e\u5728\u7f51\u7edc\u5e94\u7528\u548c\u5206\u5e03\u5f0f\u5e94\u7528\u4e2d\u4f7f\u7528\u7684\u5404\u79cd\u4e3b\u9898\u3002\u4e3b\u9898\u5212\u5206\u4e3a\u4f7f\u7528Python\u7f16\u5199\u5ba2\u6237\u7aef\u7a0b\u5e8f\u6765\u8bbf\u95ee\u5df2\u6709\u7684\u670d\u52a1\uff0c\u4ee5\u53ca\u4f7f\u7528Python\u5b9e\u73b0\u7f51\u7edc\u670d\u52a1\u7aef\u7a0b\u5e8f\u3002\u4e5f\u7ed9\u51fa\u4e86\u4e00\u4e9b\u5e38\u89c1\u7684\u6280\u672f\uff0c\u7528\u4e8e\u7f16\u5199\u6d89\u53ca\u534f\u540c\u6216\u901a\u4fe1\u7684\u7684\u4ee3\u7801\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.1 \u4f5c\u4e3a\u5ba2\u6237\u7aef\u4e0eHTTP\u670d\u52a1\u4ea4\u4e92\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u9700\u8981\u901a\u8fc7HTTP\u534f\u8bae\u4ee5\u5ba2\u6237\u7aef\u7684\u65b9\u5f0f\u8bbf\u95ee\u591a\u79cd\u670d\u52a1\u3002\u4f8b\u5982\uff0c\u4e0b\u8f7d\u6570\u636e\u6216\u8005\u4e0e\u57fa\u4e8eREST\u7684API\u8fdb\u884c\u4ea4\u4e92\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u7b80\u5355\u7684\u4e8b\u60c5\u6765\u8bf4\uff0c\u901a\u5e38\u4f7f\u7528 urllib.request \u6a21\u5757\u5c31\u591f\u4e86\u3002\u4f8b\u5982\uff0c\u53d1\u9001\u4e00\u4e2a\u7b80\u5355\u7684HTTP GET\u8bf7\u6c42\u5230\u8fdc\u7a0b\u7684\u670d\u52a1\u4e0a\uff0c\u53ef\u4ee5\u8fd9\u6837\u505a\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from urllib import request, parse\n\n# Base URL being accessed\nurl = 'http://httpbin.org/get'\n\n# Dictionary of query parameters (if any)\nparms = {\n   'name1' : 'value1',\n   'name2' : 'value2'\n}\n\n# Encode the query string\nquerystring = parse.urlencode(parms)\n\n# Make a GET request and read the response\nu = request.urlopen(url+'?' + querystring)\nresp = u.read()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u9700\u8981\u4f7f\u7528POST\u65b9\u6cd5\u5728\u8bf7\u6c42\u4e3b\u4f53\u4e2d\u53d1\u9001\u67e5\u8be2\u53c2\u6570\uff0c\u53ef\u4ee5\u5c06\u53c2\u6570\u7f16\u7801\u540e\u4f5c\u4e3a\u53ef\u9009\u53c2\u6570\u63d0\u4f9b\u7ed9 urlopen() \u51fd\u6570\uff0c\u5c31\u50cf\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from urllib import request, parse\n\n# Base URL being accessed\nurl = 'http://httpbin.org/post'\n\n# Dictionary of query parameters (if any)\nparms = {\n   'name1' : 'value1',\n   'name2' : 'value2'\n}\n\n# Encode the query string\nquerystring = parse.urlencode(parms)\n\n# Make a POST request and read the response\nu = request.urlopen(url, querystring.encode('ascii'))\nresp = u.read()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u9700\u8981\u5728\u53d1\u51fa\u7684\u8bf7\u6c42\u4e2d\u63d0\u4f9b\u4e00\u4e9b\u81ea\u5b9a\u4e49\u7684HTTP\u5934\uff0c\u4f8b\u5982\u4fee\u6539 user-agent \u5b57\u6bb5,\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u5b57\u6bb5\u503c\u7684\u5b57\u5178\uff0c\u5e76\u521b\u5efa\u4e00\u4e2aRequest\u5b9e\u4f8b\u7136\u540e\u5c06\u5176\u4f20\u7ed9 urlopen() \uff0c\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from urllib import request, parse\n...\n\n# Extra headers\nheaders = {\n    'User-agent' : 'none/ofyourbusiness',\n    'Spam' : 'Eggs'\n}\n\nreq = request.Request(url, querystring.encode('ascii'), headers=headers)\n\n# Make a request and read the response\nu = request.urlopen(req)\nresp = u.read()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u9700\u8981\u4ea4\u4e92\u7684\u670d\u52a1\u6bd4\u4e0a\u9762\u7684\u4f8b\u5b50\u90fd\u8981\u590d\u6742\uff0c\u4e5f\u8bb8\u5e94\u8be5\u53bb\u770b\u770b requests \u5e93\uff08https://pypi.python.org/pypi/requests\uff09\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u8fd9\u4e2a\u793a\u4f8b\u91c7\u7528requests\u5e93\u91cd\u65b0\u5b9e\u73b0\u4e86\u4e0a\u9762\u7684\u64cd\u4f5c\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\n\n# Base URL being accessed\nurl = 'http://httpbin.org/post'\n\n# Dictionary of query parameters (if any)\nparms = {\n   'name1' : 'value1',\n   'name2' : 'value2'\n}\n\n# Extra headers\nheaders = {\n    'User-agent' : 'none/ofyourbusiness',\n    'Spam' : 'Eggs'\n}\n\nresp = requests.post(url, data=parms, headers=headers)\n\n# Decoded text returned by the request\ntext = resp.text"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5173\u4e8erequests\u5e93\uff0c\u4e00\u4e2a\u503c\u5f97\u4e00\u63d0\u7684\u7279\u6027\u5c31\u662f\u5b83\u80fd\u4ee5\u591a\u79cd\u65b9\u5f0f\u4ece\u8bf7\u6c42\u4e2d\u8fd4\u56de\u54cd\u5e94\u7ed3\u679c\u7684\u5185\u5bb9\u3002\u4ece\u4e0a\u9762\u7684\u4ee3\u7801\u6765\u770b\uff0c resp.text \u5e26\u7ed9\u6211\u4eec\u7684\u662f\u4ee5Unicode\u89e3\u7801\u7684\u54cd\u5e94\u6587\u672c\u3002\u4f46\u662f\uff0c\u5982\u679c\u53bb\u8bbf\u95ee resp.content \uff0c\u5c31\u4f1a\u5f97\u5230\u539f\u59cb\u7684\u4e8c\u8fdb\u5236\u6570\u636e\u3002\u53e6\u4e00\u65b9\u9762\uff0c\u5982\u679c\u8bbf\u95ee resp.json \uff0c\u90a3\u4e48\u5c31\u4f1a\u5f97\u5230JSON\u683c\u5f0f\u7684\u54cd\u5e94\u5185\u5bb9\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u8fd9\u4e2a\u793a\u4f8b\u5229\u7528 requests \u5e93\u53d1\u8d77\u4e00\u4e2aHEAD\u8bf7\u6c42\uff0c\u5e76\u4ece\u54cd\u5e94\u4e2d\u63d0\u53d6\u51fa\u4e00\u4e9bHTTP\u5934\u6570\u636e\u7684\u5b57\u6bb5\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\n\nresp = requests.head('http://www.python.org/index.html')\n\nstatus = resp.status_code\nlast_modified = resp.headers['last-modified']\ncontent_type = resp.headers['content-type']\ncontent_length = resp.headers['content-length']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u5229\u7528requests\u901a\u8fc7\u57fa\u672c\u8ba4\u8bc1\u767b\u5f55Pypi\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\n\nresp = requests.get('http://pypi.python.org/pypi?:action=login',\n                    auth=('user','password'))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4e00\u4e2a\u5229\u7528requests\u5c06HTTP cookies\u4ece\u4e00\u4e2a\u8bf7\u6c42\u4f20\u9012\u5230\u53e6\u4e00\u4e2a\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\n\n# First request\nresp1 = requests.get(url)\n...\n\n# Second requests with cookies received on first requests\nresp2 = requests.get(url, cookies=resp1.cookies)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\u4f46\u5e76\u975e\u6700\u4e0d\u91cd\u8981\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\u7528requests\u4e0a\u4f20\u5185\u5bb9\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\nurl = 'http://httpbin.org/post'\nfiles = { 'file': ('data.csv', open('data.csv', 'rb')) }\n\nr = requests.post(url, files=files)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u771f\u7684\u5f88\u7b80\u5355HTTP\u5ba2\u6237\u7aef\u4ee3\u7801\uff0c\u7528\u5185\u7f6e\u7684 urllib \u6a21\u5757\u901a\u5e38\u5c31\u8db3\u591f\u4e86\u3002\u4f46\u662f\uff0c\u5982\u679c\u4f60\u8981\u505a\u7684\u4e0d\u4ec5\u4ec5\u53ea\u662f\u7b80\u5355\u7684GET\u6216POST\u8bf7\u6c42\uff0c\u90a3\u5c31\u771f\u7684\u4e0d\u80fd\u518d\u4f9d\u8d56\u5b83\u7684\u529f\u80fd\u4e86\u3002\u8fd9\u65f6\u5019\u5c31\u662f\u7b2c\u4e09\u65b9\u6a21\u5757\u6bd4\u5982 requests \u5927\u663e\u8eab\u624b\u7684\u65f6\u5019\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u51b3\u5b9a\u575a\u6301\u4f7f\u7528\u6807\u51c6\u7684\u7a0b\u5e8f\u5e93\u800c\u4e0d\u8003\u8651\u50cf requests \u8fd9\u6837\u7684\u7b2c\u4e09\u65b9\u5e93\uff0c\u90a3\u4e48\u4e5f\u8bb8\u5c31\u4e0d\u5f97\u4e0d\u4f7f\u7528\u5e95\u5c42\u7684 http.client \u6a21\u5757\u6765\u5b9e\u73b0\u81ea\u5df1\u7684\u4ee3\u7801\u3002\u6bd4\u65b9\u8bf4\uff0c\u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86\u5982\u4f55\u6267\u884c\u4e00\u4e2aHEAD\u8bf7\u6c42\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from http.client import HTTPConnection\nfrom urllib import parse\n\nc = HTTPConnection('www.python.org', 80)\nc.request('HEAD', '/index.html')\nresp = c.getresponse()\n\nprint('Status', resp.status)\nfor name, value in resp.getheaders():\n    print(name, value)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u540c\u6837\u5730\uff0c\u5982\u679c\u5fc5\u987b\u7f16\u5199\u6d89\u53ca\u4ee3\u7406\u3001\u8ba4\u8bc1\u3001cookies\u4ee5\u53ca\u5176\u4ed6\u4e00\u4e9b\u7ec6\u8282\u65b9\u9762\u7684\u4ee3\u7801\uff0c\u90a3\u4e48\u4f7f\u7528 urllib \u5c31\u663e\u5f97\u7279\u522b\u522b\u626d\u548c\u5570\u55e6\u3002\u6bd4\u65b9\u8bf4\uff0c\u4e0b\u9762\u8fd9\u4e2a\u793a\u4f8b\u5b9e\u73b0\u5728Python\u5305\u7d22\u5f15\u4e0a\u7684\u8ba4\u8bc1\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import urllib.request\n\nauth = urllib.request.HTTPBasicAuthHandler()\nauth.add_password('pypi','http://pypi.python.org','username','password')\nopener = urllib.request.build_opener(auth)\n\nr = urllib.request.Request('http://pypi.python.org/pypi?:action=login')\nu = opener.open(r)\nresp = u.read()\n\n# From here. You can access more pages using opener\n..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5766\u767d\u8bf4\uff0c\u6240\u6709\u7684\u8fd9\u4e9b\u64cd\u4f5c\u5728 requests \u5e93\u4e2d\u90fd\u53d8\u5f97\u7b80\u5355\u7684\u591a\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u6d4b\u8bd5HTTP\u5ba2\u6237\u7aef\u4ee3\u7801\u5e38\u5e38\u662f\u5f88\u4ee4\u4eba\u6cae\u4e27\u7684\uff0c\u56e0\u4e3a\u6240\u6709\u68d8\u624b\u7684\u7ec6\u8282\u95ee\u9898\u90fd\u9700\u8981\u8003\u8651\uff08\u4f8b\u5982cookies\u3001\u8ba4\u8bc1\u3001HTTP\u5934\u3001\u7f16\u7801\u65b9\u5f0f\u7b49\uff09\u3002\u8981\u5b8c\u6210\u8fd9\u4e9b\u4efb\u52a1\uff0c\u8003\u8651\u4f7f\u7528httpbin\u670d\u52a1\uff08http://httpbin.org\uff09\u3002\u8fd9\u4e2a\u7ad9\u70b9\u4f1a\u63a5\u6536\u53d1\u51fa\u7684\u8bf7\u6c42\uff0c\u7136\u540e\u4ee5JSON\u7684\u5f62\u5f0f\u5c06\u76f8\u5e94\u4fe1\u606f\u56de\u4f20\u56de\u6765\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u4ea4\u4e92\u5f0f\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import requests\nr = requests.get('http://httpbin.org/get?name=Dave&n=37',\n    headers = { 'User-agent': 'goaway/1.0' })\nresp = r.json()\nresp['headers']"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "resp['args']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u8981\u540c\u4e00\u4e2a\u771f\u6b63\u7684\u7ad9\u70b9\u8fdb\u884c\u4ea4\u4e92\u524d\uff0c\u5148\u5728 httpbin.org \u8fd9\u6837\u7684\u7f51\u7ad9\u4e0a\u505a\u5b9e\u9a8c\u5e38\u5e38\u662f\u53ef\u53d6\u7684\u529e\u6cd5\u3002\u5c24\u5176\u662f\u5f53\u6211\u4eec\u9762\u5bf93\u6b21\u767b\u5f55\u5931\u8d25\u5c31\u4f1a\u5173\u95ed\u8d26\u6237\u8fd9\u6837\u7684\u98ce\u9669\u65f6\u5c24\u4e3a\u6709\u7528\uff08\u4e0d\u8981\u5c1d\u8bd5\u81ea\u5df1\u7f16\u5199HTTP\u8ba4\u8bc1\u5ba2\u6237\u7aef\u6765\u767b\u5f55\u4f60\u7684\u94f6\u884c\u8d26\u6237\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1\u672c\u8282\u6ca1\u6709\u6d89\u53ca\uff0c request \u5e93\u8fd8\u5bf9\u8bb8\u591a\u9ad8\u7ea7\u7684HTTP\u5ba2\u6237\u7aef\u534f\u8bae\u63d0\u4f9b\u4e86\u652f\u6301\uff0c\u6bd4\u5982OAuth\u3002 requests \u6a21\u5757\u7684\u6587\u6863\uff08http://docs.python-requests.org)\u8d28\u91cf\u5f88\u9ad8\uff08\u5766\u767d\u8bf4\u6bd4\u5728\u8fd9\u77ed\u77ed\u7684\u4e00\u8282\u7684\u7bc7\u5e45\u4e2d\u6240\u63d0\u4f9b\u7684\u4efb\u4f55\u4fe1\u606f\u90fd\u597d\uff09\uff0c\u53ef\u4ee5\u53c2\u8003\u6587\u6863\u4ee5\u83b7\u5f97\u66f4\u591a\u5730\u4fe1\u606f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.2 \u521b\u5efaTCP\u670d\u52a1\u5668\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5b9e\u73b0\u4e00\u4e2a\u670d\u52a1\u5668\uff0c\u901a\u8fc7TCP\u534f\u8bae\u548c\u5ba2\u6237\u7aef\u901a\u4fe1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u521b\u5efa\u4e00\u4e2aTCP\u670d\u52a1\u5668\u7684\u4e00\u4e2a\u7b80\u5355\u65b9\u6cd5\u662f\u4f7f\u7528 socketserver \u5e93\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u5e94\u7b54\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socketserver import BaseRequestHandler, TCPServer\n\nclass EchoHandler(BaseRequestHandler):\n    def handle(self):\n        print('Got connection from', self.client_address)\n        while True:\n\n            msg = self.request.recv(8192)\n            if not msg:\n                break\n            self.request.send(msg)\n\nif __name__ == '__main__':\n    serv = TCPServer(('', 20000), EchoHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u8fd9\u6bb5\u4ee3\u7801\u4e2d\uff0c\u4f60\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7279\u6b8a\u7684\u5904\u7406\u7c7b\uff0c\u5b9e\u73b0\u4e86\u4e00\u4e2a handle() \u65b9\u6cd5\uff0c\u7528\u6765\u4e3a\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u3002\nrequest \u5c5e\u6027\u662f\u5ba2\u6237\u7aefsocket\uff0cclient_address \u6709\u5ba2\u6237\u7aef\u5730\u5740\u3002\n\u4e3a\u4e86\u6d4b\u8bd5\u8fd9\u4e2a\u670d\u52a1\u5668\uff0c\u8fd0\u884c\u5b83\u5e76\u6253\u5f00\u53e6\u5916\u4e00\u4e2aPython\u8fdb\u7a0b\u8fde\u63a5\u8fd9\u4e2a\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\ns = socket(AF_INET, SOCK_STREAM)\ns.connect(('localhost', 20000))\ns.send(b'Hello')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.recv(8192)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5f88\u591a\u65f6\u5019\uff0c\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u5b9a\u4e49\u4e00\u4e2a\u4e0d\u540c\u7684\u5904\u7406\u5668\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u4f7f\u7528 StreamRequestHandler\n\u57fa\u7c7b\u5c06\u4e00\u4e2a\u7c7b\u6587\u4ef6\u63a5\u53e3\u653e\u7f6e\u5728\u5e95\u5c42socket\u4e0a\u7684\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socketserver import StreamRequestHandler, TCPServer\n\nclass EchoHandler(StreamRequestHandler):\n    def handle(self):\n        print('Got connection from', self.client_address)\n        # self.rfile is a file-like object for reading\n        for line in self.rfile:\n            # self.wfile is a file-like object for writing\n            self.wfile.write(line)\n\nif __name__ == '__main__':\n    serv = TCPServer(('', 20000), EchoHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "socketserver \u53ef\u4ee5\u8ba9\u6211\u4eec\u5f88\u5bb9\u6613\u7684\u521b\u5efa\u7b80\u5355\u7684TCP\u670d\u52a1\u5668\u3002\n\u4f46\u662f\uff0c\u4f60\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8fd9\u79cd\u670d\u52a1\u5668\u662f\u5355\u7ebf\u7a0b\u7684\uff0c\u4e00\u6b21\u53ea\u80fd\u4e3a\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u3002\n\u5982\u679c\u4f60\u60f3\u5904\u7406\u591a\u4e2a\u5ba2\u6237\u7aef\uff0c\u53ef\u4ee5\u521d\u59cb\u5316\u4e00\u4e2a ForkingTCPServer \u6216\u8005\u662f ThreadingTCPServer \u5bf9\u8c61\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socketserver import ThreadingTCPServer\n\n\nif __name__ == '__main__':\n    serv = ThreadingTCPServer(('', 20000), EchoHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528fork\u6216\u7ebf\u7a0b\u670d\u52a1\u5668\u6709\u4e2a\u6f5c\u5728\u95ee\u9898\u5c31\u662f\u5b83\u4eec\u4f1a\u4e3a\u6bcf\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u3002\n\u7531\u4e8e\u5ba2\u6237\u7aef\u8fde\u63a5\u6570\u662f\u6ca1\u6709\u9650\u5236\u7684\uff0c\u56e0\u6b64\u4e00\u4e2a\u6076\u610f\u7684\u9ed1\u5ba2\u53ef\u4ee5\u540c\u65f6\u53d1\u9001\u5927\u91cf\u7684\u8fde\u63a5\u8ba9\u4f60\u7684\u670d\u52a1\u5668\u5954\u6e83\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u62c5\u5fc3\u8fd9\u4e2a\u95ee\u9898\uff0c\u4f60\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u9884\u5148\u5206\u914d\u5927\u5c0f\u7684\u5de5\u4f5c\u7ebf\u7a0b\u6c60\u6216\u8fdb\u7a0b\u6c60\u3002\n\u4f60\u5148\u521b\u5efa\u4e00\u4e2a\u666e\u901a\u7684\u975e\u7ebf\u7a0b\u670d\u52a1\u5668\uff0c\u7136\u540e\u5728\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u4e2d\u4f7f\u7528 serve_forever() \u65b9\u6cd5\u6765\u542f\u52a8\u5b83\u4eec\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if __name__ == '__main__':\n    from threading import Thread\n    NWORKERS = 16\n    serv = TCPServer(('', 20000), EchoHandler)\n    for n in range(NWORKERS):\n        t = Thread(target=serv.serve_forever)\n        t.daemon = True\n        t.start()\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u822c\u6765\u8bb2\uff0c\u4e00\u4e2a TCPServer \u5728\u5b9e\u4f8b\u5316\u7684\u65f6\u5019\u4f1a\u7ed1\u5b9a\u5e76\u6fc0\u6d3b\u76f8\u5e94\u7684 socket \u3002\n\u4e0d\u8fc7\uff0c\u6709\u65f6\u5019\u4f60\u60f3\u901a\u8fc7\u8bbe\u7f6e\u67d0\u4e9b\u9009\u9879\u53bb\u8c03\u6574\u5e95\u4e0b\u7684 socket` \uff0c\u53ef\u4ee5\u8bbe\u7f6e\u53c2\u6570 bind_and_activate=False \u3002\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if __name__ == '__main__':\n    serv = TCPServer(('', 20000), EchoHandler, bind_and_activate=False)\n    # Set up various socket options\n    serv.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)\n    # Bind and activate\n    serv.server_bind()\n    serv.server_activate()\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0a\u9762\u7684 socket \u9009\u9879\u662f\u4e00\u4e2a\u975e\u5e38\u666e\u904d\u7684\u914d\u7f6e\u9879\uff0c\u5b83\u5141\u8bb8\u670d\u52a1\u5668\u91cd\u65b0\u7ed1\u5b9a\u4e00\u4e2a\u4e4b\u524d\u4f7f\u7528\u8fc7\u7684\u7aef\u53e3\u53f7\u3002\n\u7531\u4e8e\u8981\u88ab\u7ecf\u5e38\u4f7f\u7528\u5230\uff0c\u5b83\u88ab\u653e\u7f6e\u5230\u7c7b\u53d8\u91cf\u4e2d\uff0c\u53ef\u4ee5\u76f4\u63a5\u5728 TCPServer \u4e0a\u9762\u8bbe\u7f6e\u3002\n\u5728\u5b9e\u4f8b\u5316\u670d\u52a1\u5668\u7684\u65f6\u5019\u53bb\u8bbe\u7f6e\u5b83\u7684\u503c\uff0c\u5982\u4e0b\u6240\u793a\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if __name__ == '__main__':\n    TCPServer.allow_reuse_address = True\n    serv = TCPServer(('', 20000), EchoHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u4e0a\u9762\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u6f14\u793a\u4e86\u4e24\u79cd\u4e0d\u540c\u7684\u5904\u7406\u5668\u57fa\u7c7b\uff08 BaseRequestHandler \u548c StreamRequestHandler \uff09\u3002\nStreamRequestHandler \u66f4\u52a0\u7075\u6d3b\u70b9\uff0c\u80fd\u901a\u8fc7\u8bbe\u7f6e\u5176\u4ed6\u7684\u7c7b\u53d8\u91cf\u6765\u652f\u6301\u4e00\u4e9b\u65b0\u7684\u7279\u6027\u3002\u6bd4\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import socket\n\nclass EchoHandler(StreamRequestHandler):\n    # Optional settings (defaults shown)\n    timeout = 5                      # Timeout on all socket operations\n    rbufsize = -1                    # Read buffer size\n    wbufsize = 0                     # Write buffer size\n    disable_nagle_algorithm = False  # Sets TCP_NODELAY socket option\n    def handle(self):\n        print('Got connection from', self.client_address)\n        try:\n            for line in self.rfile:\n                # self.wfile is a file-like object for writing\n                self.wfile.write(line)\n        except socket.timeout:\n            print('Timed out!')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u8fd8\u9700\u8981\u6ce8\u610f\u7684\u662f\u7edd\u5927\u90e8\u5206Python\u7684\u9ad8\u5c42\u7f51\u7edc\u6a21\u5757\uff08\u6bd4\u5982HTTP\u3001XML-RPC\u7b49\uff09\u90fd\u662f\u5efa\u7acb\u5728 socketserver \u529f\u80fd\u4e4b\u4e0a\u3002\n\u4e5f\u5c31\u662f\u8bf4\uff0c\u76f4\u63a5\u4f7f\u7528 socket \u5e93\u6765\u5b9e\u73b0\u670d\u52a1\u5668\u4e5f\u5e76\u4e0d\u662f\u5f88\u96be\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u4f7f\u7528 socket \u76f4\u63a5\u7f16\u7a0b\u5b9e\u73b0\u7684\u4e00\u4e2a\u670d\u52a1\u5668\u7b80\u5355\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\n\ndef echo_handler(address, client_sock):\n    print('Got connection from {}'.format(address))\n    while True:\n        msg = client_sock.recv(8192)\n        if not msg:\n            break\n        client_sock.sendall(msg)\n    client_sock.close()\n\ndef echo_server(address, backlog=5):\n    sock = socket(AF_INET, SOCK_STREAM)\n    sock.bind(address)\n    sock.listen(backlog)\n    while True:\n        client_sock, client_addr = sock.accept()\n        echo_handler(client_addr, client_sock)\n\nif __name__ == '__main__':\n    echo_server(('', 20000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.3 \u521b\u5efaUDP\u670d\u52a1\u5668\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5b9e\u73b0\u4e00\u4e2a\u57fa\u4e8eUDP\u534f\u8bae\u7684\u670d\u52a1\u5668\u6765\u4e0e\u5ba2\u6237\u7aef\u901a\u4fe1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8ddfTCP\u4e00\u6837\uff0cUDP\u670d\u52a1\u5668\u4e5f\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 socketserver \u5e93\u5f88\u5bb9\u6613\u7684\u88ab\u521b\u5efa\u3002\n\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u65f6\u95f4\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socketserver import BaseRequestHandler, UDPServer\nimport time\n\nclass TimeHandler(BaseRequestHandler):\n    def handle(self):\n        print('Got connection from', self.client_address)\n        # Get message and client socket\n        msg, sock = self.request\n        resp = time.ctime()\n        sock.sendto(resp.encode('ascii'), self.client_address)\n\nif __name__ == '__main__':\n    serv = UDPServer(('', 20000), TimeHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8ddf\u4e4b\u524d\u4e00\u6837\uff0c\u4f60\u5148\u5b9a\u4e49\u4e00\u4e2a\u5b9e\u73b0 handle() \u7279\u6b8a\u65b9\u6cd5\u7684\u7c7b\uff0c\u4e3a\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u3002\n\u8fd9\u4e2a\u7c7b\u7684 request \u5c5e\u6027\u662f\u4e00\u4e2a\u5305\u542b\u4e86\u6570\u636e\u62a5\u548c\u5e95\u5c42socket\u5bf9\u8c61\u7684\u5143\u7ec4\u3002client_address \u5305\u542b\u4e86\u5ba2\u6237\u7aef\u5730\u5740\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6211\u4eec\u6765\u6d4b\u8bd5\u4e0b\u8fd9\u4e2a\u670d\u52a1\u5668\uff0c\u9996\u5148\u8fd0\u884c\u5b83\uff0c\u7136\u540e\u6253\u5f00\u53e6\u5916\u4e00\u4e2aPython\u8fdb\u7a0b\u5411\u670d\u52a1\u5668\u53d1\u9001\u6d88\u606f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_DGRAM\ns = socket(AF_INET, SOCK_DGRAM)\ns.sendto(b'', ('localhost', 20000))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.recvfrom(8192)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u4e2a\u5178\u578b\u7684UDP\u670d\u52a1\u5668\u63a5\u6536\u5230\u8fbe\u7684\u6570\u636e\u62a5(\u6d88\u606f)\u548c\u5ba2\u6237\u7aef\u5730\u5740\u3002\u5982\u679c\u670d\u52a1\u5668\u9700\u8981\u505a\u5e94\u7b54\uff0c\n\u5b83\u8981\u7ed9\u5ba2\u6237\u7aef\u56de\u53d1\u4e00\u4e2a\u6570\u636e\u62a5\u3002\u5bf9\u4e8e\u6570\u636e\u62a5\u7684\u4f20\u9001\uff0c\n\u4f60\u5e94\u8be5\u4f7f\u7528socket\u7684 sendto() \u548c recvfrom() \u65b9\u6cd5\u3002\n\u5c3d\u7ba1\u4f20\u7edf\u7684 send() \u548c recv() \u4e5f\u53ef\u4ee5\u8fbe\u5230\u540c\u6837\u7684\u6548\u679c\uff0c\n\u4f46\u662f\u524d\u9762\u7684\u4e24\u4e2a\u65b9\u6cd5\u5bf9\u4e8eUDP\u8fde\u63a5\u800c\u8a00\u66f4\u666e\u904d\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7531\u4e8e\u6ca1\u6709\u5e95\u5c42\u7684\u8fde\u63a5\uff0cUPD\u670d\u52a1\u5668\u76f8\u5bf9\u4e8eTCP\u670d\u52a1\u5668\u6765\u8bb2\u5b9e\u73b0\u8d77\u6765\u66f4\u52a0\u7b80\u5355\u3002\n\u4e0d\u8fc7\uff0cUDP\u5929\u751f\u662f\u4e0d\u53ef\u9760\u7684\uff08\u56e0\u4e3a\u901a\u4fe1\u6ca1\u6709\u5efa\u7acb\u8fde\u63a5\uff0c\u6d88\u606f\u53ef\u80fd\u4e22\u5931\uff09\u3002\n\u56e0\u6b64\u9700\u8981\u7531\u4f60\u81ea\u5df1\u6765\u51b3\u5b9a\u8be5\u600e\u6837\u5904\u7406\u4e22\u5931\u6d88\u606f\u7684\u60c5\u51b5\u3002\u8fd9\u4e2a\u5df2\u7ecf\u4e0d\u5728\u672c\u4e66\u8ba8\u8bba\u8303\u56f4\u5185\u4e86\uff0c\n\u4e0d\u8fc7\u901a\u5e38\u6765\u8bf4\uff0c\u5982\u679c\u53ef\u9760\u6027\u5bf9\u4e8e\u4f60\u7a0b\u5e8f\u5f88\u91cd\u8981\uff0c\u4f60\u9700\u8981\u501f\u52a9\u4e8e\u5e8f\u5217\u53f7\u3001\u91cd\u8bd5\u3001\u8d85\u65f6\u4ee5\u53ca\u4e00\u4e9b\u5176\u4ed6\u65b9\u6cd5\u6765\u4fdd\u8bc1\u3002\nUDP\u901a\u5e38\u88ab\u7528\u5728\u90a3\u4e9b\u5bf9\u4e8e\u53ef\u9760\u4f20\u8f93\u8981\u6c42\u4e0d\u662f\u5f88\u9ad8\u7684\u573a\u5408\u3002\u4f8b\u5982\uff0c\u5728\u5b9e\u65f6\u5e94\u7528\u5982\u591a\u5a92\u4f53\u6d41\u4ee5\u53ca\u6e38\u620f\u9886\u57df\uff0c\n\u65e0\u9700\u8fd4\u56de\u6062\u590d\u4e22\u5931\u7684\u6570\u636e\u5305\uff08\u7a0b\u5e8f\u53ea\u9700\u7b80\u5355\u7684\u5ffd\u7565\u5b83\u5e76\u7ee7\u7eed\u5411\u524d\u8fd0\u884c\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "UDPServer \u7c7b\u662f\u5355\u7ebf\u7a0b\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u4e00\u6b21\u53ea\u80fd\u4e3a\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u3002\n\u5b9e\u9645\u4f7f\u7528\u4e2d\uff0c\u8fd9\u4e2a\u65e0\u8bba\u662f\u5bf9\u4e8eUDP\u8fd8\u662fTCP\u90fd\u4e0d\u662f\u4ec0\u4e48\u5927\u95ee\u9898\u3002\n\u5982\u679c\u4f60\u60f3\u8981\u5e76\u53d1\u64cd\u4f5c\uff0c\u53ef\u4ee5\u5b9e\u4f8b\u5316\u4e00\u4e2a ForkingUDPServer \u6216 ThreadingUDPServer \u5bf9\u8c61\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socketserver import ThreadingUDPServer\n\n   if __name__ == '__main__':\n    serv = ThreadingUDPServer(('',20000), TimeHandler)\n    serv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u76f4\u63a5\u4f7f\u7528 socket \u6765\u5b9e\u73b0\u4e00\u4e2aUDP\u670d\u52a1\u5668\u4e5f\u4e0d\u96be\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_DGRAM\nimport time\n\ndef time_server(address):\n    sock = socket(AF_INET, SOCK_DGRAM)\n    sock.bind(address)\n    while True:\n        msg, addr = sock.recvfrom(8192)\n        print('Got message from', addr)\n        resp = time.ctime()\n        sock.sendto(resp.encode('ascii'), addr)\n\nif __name__ == '__main__':\n    time_server(('', 20000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.4 \u901a\u8fc7CIDR\u5730\u5740\u751f\u6210\u5bf9\u5e94\u7684IP\u5730\u5740\u96c6\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6709\u4e00\u4e2aCIDR\u7f51\u7edc\u5730\u5740\u6bd4\u5982\u201c123.45.67.89/27\u201d\uff0c\u4f60\u60f3\u5c06\u5176\u8f6c\u6362\u6210\u5b83\u6240\u4ee3\u8868\u7684\u6240\u6709IP\n\uff08\u6bd4\u5982\uff0c\u201c123.45.67.64\u201d, \u201c123.45.67.65\u201d, \u2026, \u201c123.45.67.95\u201d)\uff09"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53ef\u4ee5\u4f7f\u7528 ipaddress \u6a21\u5757\u5f88\u5bb9\u6613\u7684\u5b9e\u73b0\u8fd9\u6837\u7684\u8ba1\u7b97\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import ipaddress\nnet = ipaddress.ip_network('123.45.67.64/27')\nnet"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "for a in net:\n    print(a)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net6 = ipaddress.ip_network('12:3456:78:90ab:cd:ef01:23:30/125')\nnet6"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "for a in net6:\n    print(a)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Network \u4e5f\u5141\u8bb8\u50cf\u6570\u7ec4\u4e00\u6837\u7684\u7d22\u5f15\u53d6\u503c\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net.num_addresses"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net[0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net[1]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net[-1]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "net[-2]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53e6\u5916\uff0c\u4f60\u8fd8\u53ef\u4ee5\u6267\u884c\u7f51\u7edc\u6210\u5458\u68c0\u67e5\u4e4b\u7c7b\u7684\u64cd\u4f5c\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "a = ipaddress.ip_address('123.45.67.69')\na in net"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "b = ipaddress.ip_address('123.45.67.123')\nb in net"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u4e2aIP\u5730\u5740\u548c\u7f51\u7edc\u5730\u5740\u80fd\u901a\u8fc7\u4e00\u4e2aIP\u63a5\u53e3\u6765\u6307\u5b9a\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "inet = ipaddress.ip_interface('123.45.67.73/27')\ninet.network"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "inet.ip"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "ipaddress \u6a21\u5757\u6709\u5f88\u591a\u7c7b\u53ef\u4ee5\u8868\u793aIP\u5730\u5740\u3001\u7f51\u7edc\u548c\u63a5\u53e3\u3002\n\u5f53\u4f60\u9700\u8981\u64cd\u4f5c\u7f51\u7edc\u5730\u5740\uff08\u6bd4\u5982\u89e3\u6790\u3001\u6253\u5370\u3001\u9a8c\u8bc1\u7b49\uff09\u7684\u65f6\u5019\u4f1a\u5f88\u6709\u7528\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u6ce8\u610f\u7684\u662f\uff0cipaddress \u6a21\u5757\u8ddf\u5176\u4ed6\u4e00\u4e9b\u548c\u7f51\u7edc\u76f8\u5173\u7684\u6a21\u5757\u6bd4\u5982 socket \u5e93\u4ea4\u96c6\u5f88\u5c11\u3002\n\u6240\u4ee5\uff0c\u4f60\u4e0d\u80fd\u4f7f\u7528 IPv4Address \u7684\u5b9e\u4f8b\u6765\u4ee3\u66ff\u4e00\u4e2a\u5730\u5740\u5b57\u7b26\u4e32\uff0c\u4f60\u9996\u5148\u5f97\u663e\u5f0f\u7684\u4f7f\u7528 str() \u8f6c\u6362\u5b83\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "a = ipaddress.ip_address('127.0.0.1')\nfrom socket import socket, AF_INET, SOCK_STREAM\ns = socket(AF_INET, SOCK_STREAM)\ns.connect((a, 8080))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.connect((str(a), 8080))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u66f4\u591a\u76f8\u5173\u5185\u5bb9\uff0c\u8bf7\u53c2\u8003 An Introduction to the ipaddress Module"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.5 \u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684REST\u63a5\u53e3\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u4f7f\u7528\u4e00\u4e2a\u7b80\u5355\u7684REST\u63a5\u53e3\u901a\u8fc7\u7f51\u7edc\u8fdc\u7a0b\u63a7\u5236\u6216\u8bbf\u95ee\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f46\u662f\u4f60\u53c8\u4e0d\u60f3\u81ea\u5df1\u53bb\u5b89\u88c5\u4e00\u4e2a\u5b8c\u6574\u7684web\u6846\u67b6\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6784\u5efa\u4e00\u4e2aREST\u98ce\u683c\u7684\u63a5\u53e3\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u662f\u521b\u5efa\u4e00\u4e2a\u57fa\u4e8eWSGI\u6807\u51c6\uff08PEP 3333\uff09\u7684\u5f88\u5c0f\u7684\u5e93\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# resty.py\n\nimport cgi\n\ndef notfound_404(environ, start_response):\n    start_response('404 Not Found', [ ('Content-type', 'text/plain') ])\n    return [b'Not Found']\n\nclass PathDispatcher:\n    def __init__(self):\n        self.pathmap = { }\n\n    def __call__(self, environ, start_response):\n        path = environ['PATH_INFO']\n        params = cgi.FieldStorage(environ['wsgi.input'],\n                                  environ=environ)\n        method = environ['REQUEST_METHOD'].lower()\n        environ['params'] = { key: params.getvalue(key) for key in params }\n        handler = self.pathmap.get((method,path), notfound_404)\n        return handler(environ, start_response)\n\n    def register(self, method, path, function):\n        self.pathmap[method.lower(), path] = function\n        return function"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u4f7f\u7528\u8fd9\u4e2a\u8c03\u5ea6\u5668\uff0c\u4f60\u53ea\u9700\u8981\u7f16\u5199\u4e0d\u540c\u7684\u5904\u7406\u5668\uff0c\u5c31\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import time\n\n_hello_resp = '''\\\n<html>\n  <head>\n     <title>Hello {name}</title>\n   </head>\n   <body>\n     <h1>Hello {name}!</h1>\n   </body>\n</html>'''\n\ndef hello_world(environ, start_response):\n    start_response('200 OK', [ ('Content-type','text/html')])\n    params = environ['params']\n    resp = _hello_resp.format(name=params.get('name'))\n    yield resp.encode('utf-8')\n\n_localtime_resp = '''\\\n<?xml version=\"1.0\"?>\n<time>\n  <year>{t.tm_year}</year>\n  <month>{t.tm_mon}</month>\n  <day>{t.tm_mday}</day>\n  <hour>{t.tm_hour}</hour>\n  <minute>{t.tm_min}</minute>\n  <second>{t.tm_sec}</second>\n</time>'''\n\ndef localtime(environ, start_response):\n    start_response('200 OK', [ ('Content-type', 'application/xml') ])\n    resp = _localtime_resp.format(t=time.localtime())\n    yield resp.encode('utf-8')\n\nif __name__ == '__main__':\n    from resty import PathDispatcher\n    from wsgiref.simple_server import make_server\n\n    # Create the dispatcher and register functions\n    dispatcher = PathDispatcher()\n    dispatcher.register('GET', '/hello', hello_world)\n    dispatcher.register('GET', '/localtime', localtime)\n\n    # Launch a basic server\n    httpd = make_server('', 8080, dispatcher)\n    print('Serving on port 8080...')\n    httpd.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u6d4b\u8bd5\u4e0b\u8fd9\u4e2a\u670d\u52a1\u5668\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u6d4f\u89c8\u5668\u6216 urllib \u548c\u5b83\u4ea4\u4e92\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "u = urlopen('http://localhost:8080/hello?name=Guido')\nprint(u.read().decode('utf-8'))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "u = urlopen('http://localhost:8080/localtime')\nprint(u.read().decode('utf-8'))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u7f16\u5199REST\u63a5\u53e3\u65f6\uff0c\u901a\u5e38\u90fd\u662f\u670d\u52a1\u4e8e\u666e\u901a\u7684HTTP\u8bf7\u6c42\u3002\u4f46\u662f\u8ddf\u90a3\u4e9b\u529f\u80fd\u5b8c\u6574\u7684\u7f51\u7ad9\u76f8\u6bd4\uff0c\u4f60\u901a\u5e38\u53ea\u9700\u8981\u5904\u7406\u6570\u636e\u3002\n\u8fd9\u4e9b\u6570\u636e\u4ee5\u5404\u79cd\u6807\u51c6\u683c\u5f0f\u7f16\u7801\uff0c\u6bd4\u5982XML\u3001JSON\u6216CSV\u3002\n\u5c3d\u7ba1\u7a0b\u5e8f\u770b\u4e0a\u53bb\u5f88\u7b80\u5355\uff0c\u4f46\u662f\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u63d0\u4f9b\u7684API\u5bf9\u4e8e\u5f88\u591a\u5e94\u7528\u7a0b\u5e8f\u6765\u8bb2\u662f\u975e\u5e38\u6709\u7528\u7684\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f8b\u5982\uff0c\u957f\u671f\u8fd0\u884c\u7684\u7a0b\u5e8f\u53ef\u80fd\u4f1a\u4f7f\u7528\u4e00\u4e2aREST API\u6765\u5b9e\u73b0\u76d1\u63a7\u6216\u8bca\u65ad\u3002\n\u5927\u6570\u636e\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528REST\u6765\u6784\u5efa\u4e00\u4e2a\u6570\u636e\u67e5\u8be2\u6216\u63d0\u53d6\u7cfb\u7edf\u3002\nREST\u8fd8\u80fd\u7528\u6765\u63a7\u5236\u786c\u4ef6\u8bbe\u5907\u6bd4\u5982\u673a\u5668\u4eba\u3001\u4f20\u611f\u5668\u3001\u5de5\u5382\u6216\u706f\u6ce1\u3002\n\u66f4\u91cd\u8981\u7684\u662f\uff0cREST API\u5df2\u7ecf\u88ab\u5927\u91cf\u5ba2\u6237\u7aef\u7f16\u7a0b\u73af\u5883\u6240\u652f\u6301\uff0c\u6bd4\u5982Javascript, Android, iOS\u7b49\u3002\n\u56e0\u6b64\uff0c\u5229\u7528\u8fd9\u79cd\u63a5\u53e3\u53ef\u4ee5\u8ba9\u4f60\u5f00\u53d1\u51fa\u66f4\u52a0\u590d\u6742\u7684\u5e94\u7528\u7a0b\u5e8f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684REST\u63a5\u53e3\uff0c\u4f60\u53ea\u9700\u8ba9\u4f60\u7684\u7a0b\u5e8f\u4ee3\u7801\u6ee1\u8db3Python\u7684WSGI\u6807\u51c6\u5373\u53ef\u3002\nWSGI\u88ab\u6807\u51c6\u5e93\u652f\u6301\uff0c\u540c\u65f6\u4e5f\u88ab\u7edd\u5927\u90e8\u5206\u7b2c\u4e09\u65b9web\u6846\u67b6\u652f\u6301\u3002\n\u56e0\u6b64\uff0c\u5982\u679c\u4f60\u7684\u4ee3\u7801\u9075\u5faa\u8fd9\u4e2a\u6807\u51c6\uff0c\u5728\u540e\u9762\u7684\u4f7f\u7528\u8fc7\u7a0b\u4e2d\u5c31\u4f1a\u66f4\u52a0\u7684\u7075\u6d3b\uff01"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728WSGI\u4e2d\uff0c\u4f60\u53ef\u4ee5\u50cf\u4e0b\u9762\u8fd9\u6837\u7ea6\u5b9a\u7684\u65b9\u5f0f\u4ee5\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\u5f62\u5f0f\u6765\u5b9e\u73b0\u4f60\u7684\u7a0b\u5e8f\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import cgi\n\ndef wsgi_app(environ, start_response):\n    pass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "environ \u5c5e\u6027\u662f\u4e00\u4e2a\u5b57\u5178\uff0c\u5305\u542b\u4e86\u4eceweb\u670d\u52a1\u5668\u5982Apache[\u53c2\u8003Internet RFC 3875]\u63d0\u4f9b\u7684CGI\u63a5\u53e3\u4e2d\u83b7\u53d6\u7684\u503c\u3002\n\u8981\u5c06\u8fd9\u4e9b\u4e0d\u540c\u7684\u503c\u63d0\u53d6\u51fa\u6765\uff0c\u4f60\u53ef\u4ee5\u50cf\u8fd9\u4e48\u8fd9\u6837\u5199\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def wsgi_app(environ, start_response):\n    method = environ['REQUEST_METHOD']\n    path = environ['PATH_INFO']\n    # Parse the query parameters\n    params = cgi.FieldStorage(environ['wsgi.input'], environ=environ)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6211\u4eec\u5c55\u793a\u4e86\u4e00\u4e9b\u5e38\u89c1\u7684\u503c\u3002environ['REQUEST_METHOD'] \u4ee3\u8868\u8bf7\u6c42\u7c7b\u578b\u5982GET\u3001POST\u3001HEAD\u7b49\u3002\nenviron['PATH_INFO'] \u8868\u793a\u88ab\u8bf7\u6c42\u8d44\u6e90\u7684\u8def\u5f84\u3002\n\u8c03\u7528 cgi.FieldStorage() \u53ef\u4ee5\u4ece\u8bf7\u6c42\u4e2d\u63d0\u53d6\u67e5\u8be2\u53c2\u6570\u5e76\u5c06\u5b83\u4eec\u653e\u5165\u4e00\u4e2a\u7c7b\u5b57\u5178\u5bf9\u8c61\u4e2d\u4ee5\u4fbf\u540e\u9762\u4f7f\u7528\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "start_response \u53c2\u6570\u662f\u4e00\u4e2a\u4e3a\u4e86\u521d\u59cb\u5316\u4e00\u4e2a\u8bf7\u6c42\u5bf9\u8c61\u800c\u5fc5\u987b\u88ab\u8c03\u7528\u7684\u51fd\u6570\u3002\n\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u8fd4\u56de\u7684HTTP\u72b6\u6001\u503c\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a(\u540d,\u503c)\u5143\u7ec4\u5217\u8868\uff0c\u7528\u6765\u6784\u5efa\u8fd4\u56de\u7684HTTP\u5934\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def wsgi_app(environ, start_response):\n    pass\n    start_response('200 OK', [('Content-type', 'text/plain')])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u8fd4\u56de\u6570\u636e\uff0c\u4e00\u4e2aWSGI\u7a0b\u5e8f\u5fc5\u987b\u8fd4\u56de\u4e00\u4e2a\u5b57\u8282\u5b57\u7b26\u4e32\u5e8f\u5217\u3002\u53ef\u4ee5\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\u4e00\u4e2a\u5217\u8868\u6765\u5b8c\u6210\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def wsgi_app(environ, start_response):\n    pass\n    start_response('200 OK', [('Content-type', 'text/plain')])\n    resp = []\n    resp.append(b'Hello World\\n')\n    resp.append(b'Goodbye!\\n')\n    return resp"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6216\u8005\uff0c\u4f60\u8fd8\u53ef\u4ee5\u4f7f\u7528 yield \uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def wsgi_app(environ, start_response):\n    pass\n    start_response('200 OK', [('Content-type', 'text/plain')])\n    yield b'Hello World\\n'\n    yield b'Goodbye!\\n'"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u91cc\u8981\u5f3a\u8c03\u7684\u4e00\u70b9\u662f\u6700\u540e\u8fd4\u56de\u7684\u5fc5\u987b\u662f\u5b57\u8282\u5b57\u7b26\u4e32\u3002\u5982\u679c\u8fd4\u56de\u7ed3\u679c\u5305\u542b\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u5fc5\u987b\u5148\u5c06\u5176\u7f16\u7801\u6210\u5b57\u8282\u3002\n\u5f53\u7136\uff0c\u5e76\u6ca1\u6709\u8981\u6c42\u4f60\u8fd4\u56de\u7684\u4e00\u5b9a\u662f\u6587\u672c\uff0c\u4f60\u53ef\u4ee5\u5f88\u8f7b\u677e\u7684\u7f16\u5199\u4e00\u4e2a\u751f\u6210\u56fe\u7247\u7684\u7a0b\u5e8f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c3d\u7ba1WSGI\u7a0b\u5e8f\u901a\u5e38\u88ab\u5b9a\u4e49\u6210\u4e00\u4e2a\u51fd\u6570\uff0c\u4e0d\u8fc7\u4f60\u4e5f\u53ef\u4ee5\u4f7f\u7528\u7c7b\u5b9e\u4f8b\u6765\u5b9e\u73b0\uff0c\u53ea\u8981\u5b83\u5b9e\u73b0\u4e86\u5408\u9002\u7684 __call__() \u65b9\u6cd5\u3002\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class WSGIApplication:\n    def __init__(self):\n        ...\n    def __call__(self, environ, start_response)\n       ..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6211\u4eec\u5df2\u7ecf\u5728\u4e0a\u9762\u4f7f\u7528\u8fd9\u79cd\u6280\u672f\u521b\u5efa PathDispatcher \u7c7b\u3002\n\u8fd9\u4e2a\u5206\u53d1\u5668\u4ec5\u4ec5\u53ea\u662f\u7ba1\u7406\u4e00\u4e2a\u5b57\u5178\uff0c\u5c06(\u65b9\u6cd5,\u8def\u5f84)\u5bf9\u6620\u5c04\u5230\u5904\u7406\u5668\u51fd\u6570\u4e0a\u9762\u3002\n\u5f53\u4e00\u4e2a\u8bf7\u6c42\u5230\u6765\u65f6\uff0c\u5b83\u7684\u65b9\u6cd5\u548c\u8def\u5f84\u88ab\u63d0\u53d6\u51fa\u6765\uff0c\u7136\u540e\u88ab\u5206\u53d1\u5230\u5bf9\u5e94\u7684\u5904\u7406\u5668\u4e0a\u9762\u53bb\u3002\n\u53e6\u5916\uff0c\u4efb\u4f55\u67e5\u8be2\u53d8\u91cf\u4f1a\u88ab\u89e3\u6790\u540e\u653e\u5230\u4e00\u4e2a\u5b57\u5178\u4e2d\uff0c\u4ee5 environ['params'] \u5f62\u5f0f\u5b58\u50a8\u3002\n\u540e\u9762\u8fd9\u4e2a\u6b65\u9aa4\u592a\u5e38\u89c1\uff0c\u6240\u4ee5\u5efa\u8bae\u4f60\u5728\u5206\u53d1\u5668\u91cc\u9762\u5b8c\u6210\uff0c\u8fd9\u6837\u53ef\u4ee5\u7701\u6389\u5f88\u591a\u91cd\u590d\u4ee3\u7801\u3002\n\u4f7f\u7528\u5206\u53d1\u5668\u7684\u65f6\u5019\uff0c\u4f60\u53ea\u9700\u7b80\u5355\u7684\u521b\u5efa\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u7136\u540e\u901a\u8fc7\u5b83\u6ce8\u518c\u5404\u79cdWSGI\u5f62\u5f0f\u7684\u51fd\u6570\u3002\n\u7f16\u5199\u8fd9\u4e9b\u51fd\u6570\u5e94\u8be5\u8d85\u7ea7\u7b80\u5355\u4e86\uff0c\u53ea\u8981\u4f60\u9075\u5faa start_response() \u51fd\u6570\u7684\u7f16\u5199\u89c4\u5219\uff0c\u5e76\u4e14\u6700\u540e\u8fd4\u56de\u5b57\u8282\u5b57\u7b26\u4e32\u5373\u53ef\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5f53\u7f16\u5199\u8fd9\u79cd\u51fd\u6570\u7684\u65f6\u5019\u8fd8\u9700\u6ce8\u610f\u7684\u4e00\u70b9\u5c31\u662f\u5bf9\u4e8e\u5b57\u7b26\u4e32\u6a21\u677f\u7684\u4f7f\u7528\u3002\n\u6ca1\u4eba\u613f\u610f\u5199\u90a3\u79cd\u5230\u5904\u6df7\u5408\u7740 print() \u51fd\u6570 \u3001XML\u548c\u5927\u91cf\u683c\u5f0f\u5316\u64cd\u4f5c\u7684\u4ee3\u7801\u3002\n\u6211\u4eec\u4e0a\u9762\u4f7f\u7528\u4e86\u4e09\u5f15\u53f7\u5305\u542b\u7684\u9884\u5148\u5b9a\u4e49\u597d\u7684\u5b57\u7b26\u4e32\u6a21\u677f\u3002\n\u8fd9\u79cd\u65b9\u5f0f\u7684\u53ef\u4ee5\u8ba9\u6211\u4eec\u5f88\u5bb9\u6613\u7684\u5728\u4ee5\u540e\u4fee\u6539\u8f93\u51fa\u683c\u5f0f(\u53ea\u9700\u8981\u4fee\u6539\u6a21\u677f\u672c\u8eab\uff0c\u800c\u4e0d\u7528\u52a8\u4efb\u4f55\u4f7f\u7528\u5b83\u7684\u5730\u65b9)\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6700\u540e\uff0c\u4f7f\u7528WSGI\u8fd8\u6709\u4e00\u4e2a\u5f88\u91cd\u8981\u7684\u90e8\u5206\u5c31\u662f\u6ca1\u6709\u4ec0\u4e48\u5730\u65b9\u662f\u9488\u5bf9\u7279\u5b9aweb\u670d\u52a1\u5668\u7684\u3002\n\u56e0\u4e3a\u6807\u51c6\u5bf9\u4e8e\u670d\u52a1\u5668\u548c\u6846\u67b6\u662f\u4e2d\u7acb\u7684\uff0c\u4f60\u53ef\u4ee5\u5c06\u4f60\u7684\u7a0b\u5e8f\u653e\u5165\u4efb\u4f55\u7c7b\u578b\u670d\u52a1\u5668\u4e2d\u3002\n\u6211\u4eec\u4f7f\u7528\u4e0b\u9762\u7684\u4ee3\u7801\u6d4b\u8bd5\u6d4b\u8bd5\u672c\u8282\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if __name__ == '__main__':\n    from wsgiref.simple_server import make_server\n\n    # Create the dispatcher and register functions\n    dispatcher = PathDispatcher()\n    pass\n\n    # Launch a basic server\n    httpd = make_server('', 8080, dispatcher)\n    print('Serving on port 8080...')\n    httpd.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0a\u9762\u4ee3\u7801\u521b\u5efa\u4e86\u4e00\u4e2a\u7b80\u5355\u7684\u670d\u52a1\u5668\uff0c\u7136\u540e\u4f60\u5c31\u53ef\u4ee5\u6765\u6d4b\u8bd5\u4e0b\u4f60\u7684\u5b9e\u73b0\u662f\u5426\u80fd\u6b63\u5e38\u5de5\u4f5c\u3002\n\u6700\u540e\uff0c\u5f53\u4f60\u51c6\u5907\u8fdb\u4e00\u6b65\u6269\u5c55\u4f60\u7684\u7a0b\u5e8f\u7684\u65f6\u5019\uff0c\u4f60\u53ef\u4ee5\u4fee\u6539\u8fd9\u4e2a\u4ee3\u7801\uff0c\u8ba9\u5b83\u53ef\u4ee5\u4e3a\u7279\u5b9a\u670d\u52a1\u5668\u5de5\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "WSGI\u672c\u8eab\u662f\u4e00\u4e2a\u5f88\u5c0f\u7684\u6807\u51c6\u3002\u56e0\u6b64\u5b83\u5e76\u6ca1\u6709\u63d0\u4f9b\u4e00\u4e9b\u9ad8\u7ea7\u7684\u7279\u6027\u6bd4\u5982\u8ba4\u8bc1\u3001cookies\u3001\u91cd\u5b9a\u5411\u7b49\u3002\n\u8fd9\u4e9b\u4f60\u81ea\u5df1\u5b9e\u73b0\u8d77\u6765\u4e5f\u4e0d\u96be\u3002\u4e0d\u8fc7\u5982\u679c\u4f60\u60f3\u8981\u66f4\u591a\u7684\u652f\u6301\uff0c\u53ef\u4ee5\u8003\u8651\u7b2c\u4e09\u65b9\u5e93\uff0c\u6bd4\u5982 WebOb \u6216\u8005 Paste"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.6 \u901a\u8fc7XML-RPC\u5b9e\u73b0\u7b80\u5355\u7684\u8fdc\u7a0b\u8c03\u7528\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u627e\u5230\u4e00\u4e2a\u7b80\u5355\u7684\u65b9\u5f0f\u53bb\u6267\u884c\u8fd0\u884c\u5728\u8fdc\u7a0b\u673a\u5668\u4e0a\u9762\u7684Python\u7a0b\u5e8f\u4e2d\u7684\u51fd\u6570\u6216\u65b9\u6cd5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u73b0\u4e00\u4e2a\u8fdc\u7a0b\u65b9\u6cd5\u8c03\u7528\u7684\u6700\u7b80\u5355\u65b9\u5f0f\u662f\u4f7f\u7528XML-RPC\u3002\u4e0b\u9762\u6211\u4eec\u6f14\u793a\u4e00\u4e0b\u4e00\u4e2a\u5b9e\u73b0\u4e86\u952e-\u503c\u5b58\u50a8\u529f\u80fd\u7684\u7b80\u5355\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from xmlrpc.server import SimpleXMLRPCServer\n\nclass KeyValueServer:\n    _rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']\n    def __init__(self, address):\n        self._data = {}\n        self._serv = SimpleXMLRPCServer(address, allow_none=True)\n        for name in self._rpc_methods_:\n            self._serv.register_function(getattr(self, name))\n\n    def get(self, name):\n        return self._data[name]\n\n    def set(self, name, value):\n        self._data[name] = value\n\n    def delete(self, name):\n        del self._data[name]\n\n    def exists(self, name):\n        return name in self._data\n\n    def keys(self):\n        return list(self._data)\n\n    def serve_forever(self):\n        self._serv.serve_forever()\n\n# Example\nif __name__ == '__main__':\n    kvserv = KeyValueServer(('', 15000))\n    kvserv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u6211\u4eec\u4ece\u4e00\u4e2a\u5ba2\u6237\u7aef\u673a\u5668\u4e0a\u9762\u6765\u8bbf\u95ee\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from xmlrpc.client import ServerProxy\ns = ServerProxy('http://localhost:15000', allow_none=True)\ns.set('foo', 'bar')\ns.set('spam', [1, 2, 3])\ns.keys()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.get('foo')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.get('spam')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.delete('spam')\ns.exists('spam')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "XML-RPC \u53ef\u4ee5\u8ba9\u6211\u4eec\u5f88\u5bb9\u6613\u7684\u6784\u9020\u4e00\u4e2a\u7b80\u5355\u7684\u8fdc\u7a0b\u8c03\u7528\u670d\u52a1\u3002\u4f60\u6240\u9700\u8981\u505a\u7684\u4ec5\u4ec5\u662f\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u5668\u5b9e\u4f8b\uff0c\n\u901a\u8fc7\u5b83\u7684\u65b9\u6cd5 register_function() \u6765\u6ce8\u518c\u51fd\u6570\uff0c\u7136\u540e\u4f7f\u7528\u65b9\u6cd5 serve_forever() \u542f\u52a8\u5b83\u3002\n\u5728\u4e0a\u9762\u6211\u4eec\u5c06\u8fd9\u4e9b\u6b65\u9aa4\u653e\u5728\u4e00\u8d77\u5199\u5230\u4e00\u4e2a\u7c7b\u4e2d\uff0c\u4e0d\u591f\u8fd9\u5e76\u4e0d\u662f\u5fc5\u987b\u7684\u3002\u6bd4\u5982\u4f60\u8fd8\u53ef\u4ee5\u50cf\u4e0b\u9762\u8fd9\u6837\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u5668\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from xmlrpc.server import SimpleXMLRPCServer\ndef add(x,y):\n    return x+y\n\nserv = SimpleXMLRPCServer(('', 15000))\nserv.register_function(add)\nserv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "XML-RPC\u66b4\u9732\u51fa\u6765\u7684\u51fd\u6570\u53ea\u80fd\u9002\u7528\u4e8e\u90e8\u5206\u6570\u636e\u7c7b\u578b\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u6574\u5f62\u3001\u5217\u8868\u548c\u5b57\u5178\u3002\n\u5bf9\u4e8e\u5176\u4ed6\u7c7b\u578b\u5c31\u5f97\u9700\u8981\u505a\u4e9b\u989d\u5916\u7684\u529f\u8bfe\u4e86\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u60f3\u901a\u8fc7 XML-RPC \u4f20\u9012\u4e00\u4e2a\u5bf9\u8c61\u5b9e\u4f8b\uff0c\u5b9e\u9645\u4e0a\u53ea\u6709\u4ed6\u7684\u5b9e\u4f8b\u5b57\u5178\u88ab\u5904\u7406\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class Point:\n    def __init__(self, x, y):\n            self.x = x\n            self.y = y\np = Point(2, 3)\ns.set('foo', p)\ns.get('foo')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7c7b\u4f3c\u7684\uff0c\u5bf9\u4e8e\u4e8c\u8fdb\u5236\u6570\u636e\u7684\u5904\u7406\u4e5f\u8ddf\u4f60\u60f3\u8c61\u7684\u4e0d\u592a\u4e00\u6837\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.set('foo', b'Hello World')\ns.get('foo')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "_.data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u822c\u6765\u8bb2\uff0c\u4f60\u4e0d\u5e94\u8be5\u5c06 XML-RPC \u670d\u52a1\u4ee5\u516c\u5171API\u7684\u65b9\u5f0f\u66b4\u9732\u51fa\u6765\u3002\n\u5bf9\u4e8e\u8fd9\u79cd\u60c5\u51b5\uff0c\u901a\u5e38\u5206\u5e03\u5f0f\u5e94\u7528\u7a0b\u5e8f\u4f1a\u662f\u4e00\u4e2a\u66f4\u597d\u7684\u9009\u62e9\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "XML-RPC\u7684\u4e00\u4e2a\u7f3a\u70b9\u662f\u5b83\u7684\u6027\u80fd\u3002SimpleXMLRPCServer \u7684\u5b9e\u73b0\u662f\u5355\u7ebf\u7a0b\u7684\uff0c\n\u6240\u4ee5\u5b83\u4e0d\u9002\u5408\u4e8e\u5927\u578b\u7a0b\u5e8f\uff0c\u5c3d\u7ba1\u6211\u4eec\u572811.2\u5c0f\u8282\u4e2d\u6f14\u793a\u8fc7\u5b83\u662f\u53ef\u4ee5\u901a\u8fc7\u591a\u7ebf\u7a0b\u6765\u6267\u884c\u7684\u3002\n\u53e6\u5916\uff0c\u7531\u4e8e XML-RPC \u5c06\u6240\u6709\u6570\u636e\u90fd\u5e8f\u5217\u5316\u4e3aXML\u683c\u5f0f\uff0c\u6240\u4ee5\u5b83\u4f1a\u6bd4\u5176\u4ed6\u7684\u65b9\u5f0f\u8fd0\u884c\u7684\u6162\u4e00\u4e9b\u3002\n\u4f46\u662f\u5b83\u4e5f\u6709\u4f18\u70b9\uff0c\u8fd9\u79cd\u65b9\u5f0f\u7684\u7f16\u7801\u53ef\u4ee5\u88ab\u7edd\u5927\u90e8\u5206\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u652f\u6301\u3002\n\u901a\u8fc7\u4f7f\u7528\u8fd9\u79cd\u65b9\u5f0f\uff0c\u5176\u4ed6\u8bed\u8a00\u7684\u5ba2\u6237\u7aef\u7a0b\u5e8f\u90fd\u80fd\u8bbf\u95ee\u4f60\u7684\u670d\u52a1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u867d\u7136XML-RPC\u6709\u5f88\u591a\u7f3a\u70b9\uff0c\u4f46\u662f\u5982\u679c\u4f60\u9700\u8981\u5feb\u901f\u6784\u5efa\u4e00\u4e2a\u7b80\u5355\u8fdc\u7a0b\u8fc7\u7a0b\u8c03\u7528\u7cfb\u7edf\u7684\u8bdd\uff0c\u5b83\u4ecd\u7136\u503c\u5f97\u53bb\u5b66\u4e60\u7684\u3002\n\u6709\u65f6\u5019\uff0c\u7b80\u5355\u7684\u65b9\u6848\u5c31\u5df2\u7ecf\u8db3\u591f\u4e86\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.7 \u5728\u4e0d\u540c\u7684Python\u89e3\u91ca\u5668\u4e4b\u95f4\u4ea4\u4e92\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5728\u4e0d\u540c\u7684\u673a\u5668\u4e0a\u9762\u8fd0\u884c\u7740\u591a\u4e2aPython\u89e3\u91ca\u5668\u5b9e\u4f8b\uff0c\u5e76\u5e0c\u671b\u80fd\u591f\u5728\u8fd9\u4e9b\u89e3\u91ca\u5668\u4e4b\u95f4\u901a\u8fc7\u6d88\u606f\u6765\u4ea4\u6362\u6570\u636e\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u901a\u8fc7\u4f7f\u7528 multiprocessing.connection \u6a21\u5757\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u5b9e\u73b0\u89e3\u91ca\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u5e94\u7b54\u670d\u52a1\u5668\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from multiprocessing.connection import Listener\nimport traceback\n\ndef echo_client(conn):\n    try:\n        while True:\n            msg = conn.recv()\n            conn.send(msg)\n    except EOFError:\n        print('Connection closed')\n\ndef echo_server(address, authkey):\n    serv = Listener(address, authkey=authkey)\n    while True:\n        try:\n            client = serv.accept()\n\n            echo_client(client)\n        except Exception:\n            traceback.print_exc()\n\necho_server(('', 25000), authkey=b'peekaboo')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7136\u540e\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u5668\u5e76\u53d1\u9001\u6d88\u606f\u7684\u7b80\u5355\u793a\u4f8b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from multiprocessing.connection import Client\nc = Client(('localhost', 25000), authkey=b'peekaboo')\nc.send('hello')\nc.recv()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "c.send(42)\nc.recv()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "c.send([1, 2, 3, 4, 5])\nc.recv()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8ddf\u5e95\u5c42socket\u4e0d\u540c\u7684\u662f\uff0c\u6bcf\u4e2a\u6d88\u606f\u4f1a\u5b8c\u6574\u4fdd\u5b58\uff08\u6bcf\u4e00\u4e2a\u901a\u8fc7send()\u53d1\u9001\u7684\u5bf9\u8c61\u80fd\u901a\u8fc7recv()\u6765\u5b8c\u6574\u63a5\u53d7\uff09\u3002\n\u53e6\u5916\uff0c\u6240\u6709\u5bf9\u8c61\u4f1a\u901a\u8fc7pickle\u5e8f\u5217\u5316\u3002\u56e0\u6b64\uff0c\u4efb\u4f55\u517c\u5bb9pickle\u7684\u5bf9\u8c61\u90fd\u80fd\u5728\u6b64\u8fde\u63a5\u4e0a\u9762\u88ab\u53d1\u9001\u548c\u63a5\u53d7\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u76ee\u524d\u6709\u5f88\u591a\u7528\u6765\u5b9e\u73b0\u5404\u79cd\u6d88\u606f\u4f20\u8f93\u7684\u5305\u548c\u51fd\u6570\u5e93\uff0c\u6bd4\u5982ZeroMQ\u3001Celery\u7b49\u3002\n\u4f60\u8fd8\u6709\u53e6\u5916\u4e00\u79cd\u9009\u62e9\u5c31\u662f\u81ea\u5df1\u5728\u5e95\u5c42socket\u57fa\u7840\u4e4b\u4e0a\u6765\u5b9e\u73b0\u4e00\u4e2a\u6d88\u606f\u4f20\u8f93\u5c42\u3002\n\u4f46\u662f\u4f60\u60f3\u8981\u7b80\u5355\u4e00\u70b9\u7684\u65b9\u6848\uff0c\u90a3\u4e48\u8fd9\u65f6\u5019 multiprocessing.connection \u5c31\u6d3e\u4e0a\u7528\u573a\u4e86\u3002\n\u4ec5\u4ec5\u4f7f\u7528\u4e00\u4e9b\u7b80\u5355\u7684\u8bed\u53e5\u5373\u53ef\u5b9e\u73b0\u591a\u4e2a\u89e3\u91ca\u5668\u4e4b\u95f4\u7684\u6d88\u606f\u901a\u4fe1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u7684\u89e3\u91ca\u5668\u8fd0\u884c\u5728\u540c\u4e00\u53f0\u673a\u5668\u4e0a\u9762\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528\u53e6\u5916\u7684\u901a\u4fe1\u673a\u5236\uff0c\u6bd4\u5982Unix\u57df\u5957\u63a5\u5b57\u6216\u8005\u662fWindows\u547d\u540d\u7ba1\u9053\u3002\n\u8981\u60f3\u4f7f\u7528UNIX\u57df\u5957\u63a5\u5b57\u6765\u521b\u5efa\u4e00\u4e2a\u8fde\u63a5\uff0c\u53ea\u9700\u7b80\u5355\u7684\u5c06\u5730\u5740\u6539\u5199\u4e00\u4e2a\u6587\u4ef6\u540d\u5373\u53ef\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s = Listener('/tmp/myconn', authkey=b'peekaboo')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u60f3\u4f7f\u7528Windows\u547d\u540d\u7ba1\u9053\u6765\u521b\u5efa\u8fde\u63a5\uff0c\u53ea\u9700\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\u4e00\u4e2a\u6587\u4ef6\u540d\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s = Listener(r'\\\\.\\pipe\\myconn', authkey=b'peekaboo')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u4e2a\u901a\u7528\u51c6\u5219\u662f\uff0c\u4f60\u4e0d\u8981\u4f7f\u7528 multiprocessing \u6765\u5b9e\u73b0\u4e00\u4e2a\u5bf9\u5916\u7684\u516c\u5171\u670d\u52a1\u3002\nClient() \u548c Listener() \u4e2d\u7684 authkey \u53c2\u6570\u7528\u6765\u8ba4\u8bc1\u53d1\u8d77\u8fde\u63a5\u7684\u7ec8\u7aef\u7528\u6237\u3002\n\u5982\u679c\u5bc6\u94a5\u4e0d\u5bf9\u4f1a\u4ea7\u751f\u4e00\u4e2a\u5f02\u5e38\u3002\u6b64\u5916\uff0c\u8be5\u6a21\u5757\u6700\u9002\u5408\u7528\u6765\u5efa\u7acb\u957f\u8fde\u63a5\uff08\u800c\u4e0d\u662f\u5927\u91cf\u7684\u77ed\u8fde\u63a5\uff09\uff0c\n\u4f8b\u5982\uff0c\u4e24\u4e2a\u89e3\u91ca\u5668\u4e4b\u95f4\u542f\u52a8\u540e\u5c31\u5f00\u59cb\u5efa\u7acb\u8fde\u63a5\u5e76\u5728\u5904\u7406\u67d0\u4e2a\u95ee\u9898\u8fc7\u7a0b\u4e2d\u4f1a\u4e00\u76f4\u4fdd\u6301\u8fde\u63a5\u72b6\u6001\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u9700\u8981\u5bf9\u5e95\u5c42\u8fde\u63a5\u505a\u66f4\u591a\u7684\u63a7\u5236\uff0c\u6bd4\u5982\u9700\u8981\u652f\u6301\u8d85\u65f6\u3001\u975e\u963b\u585eI/O\u6216\u5176\u4ed6\u7c7b\u4f3c\u7684\u7279\u6027\uff0c\n\u4f60\u6700\u597d\u4f7f\u7528\u53e6\u5916\u7684\u5e93\u6216\u8005\u662f\u5728\u9ad8\u5c42socket\u4e0a\u6765\u5b9e\u73b0\u8fd9\u4e9b\u7279\u6027\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.8 \u5b9e\u73b0\u8fdc\u7a0b\u65b9\u6cd5\u8c03\u7528\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5728\u4e00\u4e2a\u6d88\u606f\u4f20\u8f93\u5c42\u5982 sockets \u3001multiprocessing connections \u6216 ZeroMQ\n\u7684\u57fa\u7840\u4e4b\u4e0a\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u8fdc\u7a0b\u8fc7\u7a0b\u8c03\u7528\uff08RPC\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5c06\u51fd\u6570\u8bf7\u6c42\u3001\u53c2\u6570\u548c\u8fd4\u56de\u503c\u4f7f\u7528pickle\u7f16\u7801\u540e\uff0c\u5728\u4e0d\u540c\u7684\u89e3\u91ca\u5668\u76f4\u63a5\u4f20\u9001pickle\u5b57\u8282\u5b57\u7b26\u4e32\uff0c\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u5b9e\u73b0RPC\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684PRC\u5904\u7406\u5668\uff0c\u53ef\u4ee5\u88ab\u6574\u5408\u5230\u4e00\u4e2a\u670d\u52a1\u5668\u4e2d\u53bb\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# rpcserver.py\n\nimport pickle\nclass RPCHandler:\n    def __init__(self):\n        self._functions = { }\n\n    def register_function(self, func):\n        self._functions[func.__name__] = func\n\n    def handle_connection(self, connection):\n        try:\n            while True:\n                # Receive a message\n                func_name, args, kwargs = pickle.loads(connection.recv())\n                # Run the RPC and send a response\n                try:\n                    r = self._functions[func_name](*args,**kwargs)\n                    connection.send(pickle.dumps(r))\n                except Exception as e:\n                    connection.send(pickle.dumps(e))\n        except EOFError:\n             pass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u4f7f\u7528\u8fd9\u4e2a\u5904\u7406\u5668\uff0c\u4f60\u9700\u8981\u5c06\u5b83\u52a0\u5165\u5230\u4e00\u4e2a\u6d88\u606f\u670d\u52a1\u5668\u4e2d\u3002\u4f60\u6709\u5f88\u591a\u79cd\u9009\u62e9\uff0c\n\u4f46\u662f\u4f7f\u7528 multiprocessing \u5e93\u662f\u6700\u7b80\u5355\u7684\u3002\u4e0b\u9762\u662f\u4e00\u4e2aRPC\u670d\u52a1\u5668\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from multiprocessing.connection import Listener\nfrom threading import Thread\n\ndef rpc_server(handler, address, authkey):\n    sock = Listener(address, authkey=authkey)\n    while True:\n        client = sock.accept()\n        t = Thread(target=handler.handle_connection, args=(client,))\n        t.daemon = True\n        t.start()\n\n# Some remote functions\ndef add(x, y):\n    return x + y\n\ndef sub(x, y):\n    return x - y\n\n# Register with a handler\nhandler = RPCHandler()\nhandler.register_function(add)\nhandler.register_function(sub)\n\n# Run the server\nrpc_server(handler, ('localhost', 17000), authkey=b'peekaboo')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u4ece\u4e00\u4e2a\u8fdc\u7a0b\u5ba2\u6237\u7aef\u8bbf\u95ee\u670d\u52a1\u5668\uff0c\u4f60\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u5bf9\u5e94\u7684\u7528\u6765\u4f20\u9001\u8bf7\u6c42\u7684RPC\u4ee3\u7406\u7c7b\u3002\u4f8b\u5982"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import pickle\n\nclass RPCProxy:\n    def __init__(self, connection):\n        self._connection = connection\n    def __getattr__(self, name):\n        def do_rpc(*args, **kwargs):\n            self._connection.send(pickle.dumps((name, args, kwargs)))\n            result = pickle.loads(self._connection.recv())\n            if isinstance(result, Exception):\n                raise result\n            return result\n        return do_rpc"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u4f7f\u7528\u8fd9\u4e2a\u4ee3\u7406\u7c7b\uff0c\u4f60\u9700\u8981\u5c06\u5176\u5305\u88c5\u5230\u4e00\u4e2a\u670d\u52a1\u5668\u7684\u8fde\u63a5\u4e0a\u9762\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from multiprocessing.connection import Client\nc = Client(('localhost', 17000), authkey=b'peekaboo')\nproxy = RPCProxy(c)\nproxy.add(2, 3)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "proxy.sub(2, 3)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "proxy.sub([1, 2], 4)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u6ce8\u610f\u7684\u662f\u5f88\u591a\u6d88\u606f\u5c42\uff08\u6bd4\u5982 multiprocessing \uff09\u5df2\u7ecf\u4f7f\u7528pickle\u5e8f\u5217\u5316\u4e86\u6570\u636e\u3002\n\u5982\u679c\u662f\u8fd9\u6837\u7684\u8bdd\uff0c\u5bf9 pickle.dumps() \u548c pickle.loads() \u7684\u8c03\u7528\u8981\u53bb\u6389\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "RPCHandler \u548c RPCProxy \u7684\u57fa\u672c\u601d\u8def\u662f\u5f88\u6bd4\u8f83\u7b80\u5355\u7684\u3002\n\u5982\u679c\u4e00\u4e2a\u5ba2\u6237\u7aef\u60f3\u8981\u8c03\u7528\u4e00\u4e2a\u8fdc\u7a0b\u51fd\u6570\uff0c\u6bd4\u5982 foo(1, 2, z=3)\n,\u4ee3\u7406\u7c7b\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e86\u51fd\u6570\u540d\u548c\u53c2\u6570\u7684\u5143\u7ec4 ('foo', (1, 2), {'z': 3}) \u3002\n\u8fd9\u4e2a\u5143\u7ec4\u88abpickle\u5e8f\u5217\u5316\u540e\u901a\u8fc7\u7f51\u7edc\u8fde\u63a5\u53d1\u751f\u51fa\u53bb\u3002\n\u8fd9\u4e00\u6b65\u5728 RPCProxy \u7684 __getattr__() \u65b9\u6cd5\u8fd4\u56de\u7684 do_rpc() \u95ed\u5305\u4e2d\u5b8c\u6210\u3002\n\u670d\u52a1\u5668\u63a5\u6536\u540e\u901a\u8fc7pickle\u53cd\u5e8f\u5217\u5316\u6d88\u606f\uff0c\u67e5\u627e\u51fd\u6570\u540d\u770b\u770b\u662f\u5426\u5df2\u7ecf\u6ce8\u518c\u8fc7\uff0c\u7136\u540e\u6267\u884c\u76f8\u5e94\u7684\u51fd\u6570\u3002\n\u6267\u884c\u7ed3\u679c(\u6216\u5f02\u5e38)\u88abpickle\u5e8f\u5217\u5316\u540e\u8fd4\u56de\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef\u3002\u6211\u4eec\u7684\u5b9e\u4f8b\u9700\u8981\u4f9d\u8d56 multiprocessing \u8fdb\u884c\u901a\u4fe1\u3002\n\u4e0d\u8fc7\uff0c\u8fd9\u79cd\u65b9\u5f0f\u53ef\u4ee5\u9002\u7528\u4e8e\u5176\u4ed6\u4efb\u4f55\u6d88\u606f\u7cfb\u7edf\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u60f3\u5728ZeroMQ\u4e4b\u4e0a\u5b9e\u4e60RPC\uff0c\n\u4ec5\u4ec5\u53ea\u9700\u8981\u5c06\u8fde\u63a5\u5bf9\u8c61\u6362\u6210\u5408\u9002\u7684ZeroMQ\u7684socket\u5bf9\u8c61\u5373\u53ef\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7531\u4e8e\u5e95\u5c42\u9700\u8981\u4f9d\u8d56pickle\uff0c\u90a3\u4e48\u5b89\u5168\u95ee\u9898\u5c31\u9700\u8981\u8003\u8651\u4e86\n\uff08\u56e0\u4e3a\u4e00\u4e2a\u806a\u660e\u7684\u9ed1\u5ba2\u53ef\u4ee5\u521b\u5efa\u7279\u5b9a\u7684\u6d88\u606f\uff0c\u80fd\u591f\u8ba9\u4efb\u610f\u51fd\u6570\u901a\u8fc7pickle\u53cd\u5e8f\u5217\u5316\u540e\u88ab\u6267\u884c\uff09\u3002\n\u56e0\u6b64\u4f60\u6c38\u8fdc\u4e0d\u8981\u5141\u8bb8\u6765\u81ea\u4e0d\u4fe1\u4efb\u6216\u672a\u8ba4\u8bc1\u7684\u5ba2\u6237\u7aef\u7684RPC\u3002\u7279\u522b\u662f\u4f60\u7edd\u5bf9\u4e0d\u8981\u5141\u8bb8\u6765\u81eaInternet\u7684\u4efb\u610f\u673a\u5668\u7684\u8bbf\u95ee\uff0c\n\u8fd9\u79cd\u53ea\u80fd\u5728\u5185\u90e8\u88ab\u4f7f\u7528\uff0c\u4f4d\u4e8e\u9632\u706b\u5899\u540e\u9762\u5e76\u4e14\u4e0d\u8981\u5bf9\u5916\u66b4\u9732\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f5c\u4e3apickle\u7684\u66ff\u4ee3\uff0c\u4f60\u4e5f\u8bb8\u53ef\u4ee5\u8003\u8651\u4f7f\u7528JSON\u3001XML\u6216\u4e00\u4e9b\u5176\u4ed6\u7684\u7f16\u7801\u683c\u5f0f\u6765\u5e8f\u5217\u5316\u6d88\u606f\u3002\n\u4f8b\u5982\uff0c\u672c\u673a\u5b9e\u4f8b\u53ef\u4ee5\u5f88\u5bb9\u6613\u7684\u6539\u5199\u6210JSON\u7f16\u7801\u65b9\u6848\u3002\u8fd8\u9700\u8981\u5c06 pickle.loads() \u548c  pickle.dumps()\n\u66ff\u6362\u6210 json.loads() \u548c json.dumps() \u5373\u53ef\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# jsonrpcserver.py\nimport json\n\nclass RPCHandler:\n    def __init__(self):\n        self._functions = { }\n\n    def register_function(self, func):\n        self._functions[func.__name__] = func\n\n    def handle_connection(self, connection):\n        try:\n            while True:\n                # Receive a message\n                func_name, args, kwargs = json.loads(connection.recv())\n                # Run the RPC and send a response\n                try:\n                    r = self._functions[func_name](*args,**kwargs)\n                    connection.send(json.dumps(r))\n                except Exception as e:\n                    connection.send(json.dumps(str(e)))\n        except EOFError:\n             pass\n\n# jsonrpcclient.py\nimport json\n\nclass RPCProxy:\n    def __init__(self, connection):\n        self._connection = connection\n    def __getattr__(self, name):\n        def do_rpc(*args, **kwargs):\n            self._connection.send(json.dumps((name, args, kwargs)))\n            result = json.loads(self._connection.recv())\n            return result\n        return do_rpc"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u73b0RPC\u7684\u4e00\u4e2a\u6bd4\u8f83\u590d\u6742\u7684\u95ee\u9898\u662f\u5982\u4f55\u53bb\u5904\u7406\u5f02\u5e38\u3002\u81f3\u5c11\uff0c\u5f53\u65b9\u6cd5\u4ea7\u751f\u5f02\u5e38\u65f6\u670d\u52a1\u5668\u4e0d\u5e94\u8be5\u5954\u6e83\u3002\n\u56e0\u6b64\uff0c\u8fd4\u56de\u7ed9\u5ba2\u6237\u7aef\u7684\u5f02\u5e38\u6240\u4ee3\u8868\u7684\u542b\u4e49\u5c31\u8981\u597d\u597d\u8bbe\u8ba1\u4e86\u3002\n\u5982\u679c\u4f60\u4f7f\u7528pickle\uff0c\u5f02\u5e38\u5bf9\u8c61\u5b9e\u4f8b\u5728\u5ba2\u6237\u7aef\u80fd\u88ab\u53cd\u5e8f\u5217\u5316\u5e76\u629b\u51fa\u3002\u5982\u679c\u4f60\u4f7f\u7528\u5176\u4ed6\u7684\u534f\u8bae\uff0c\u90a3\u5f97\u60f3\u60f3\u53e6\u5916\u7684\u65b9\u6cd5\u4e86\u3002\n\u4e0d\u8fc7\u81f3\u5c11\uff0c\u4f60\u5e94\u8be5\u5728\u54cd\u5e94\u4e2d\u8fd4\u56de\u5f02\u5e38\u5b57\u7b26\u4e32\u3002\u6211\u4eec\u5728JSON\u7684\u4f8b\u5b50\u4e2d\u5c31\u662f\u4f7f\u7528\u7684\u8fd9\u79cd\u65b9\u5f0f\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u5176\u4ed6\u7684RPC\u5b9e\u73b0\u4f8b\u5b50\uff0c\u6211\u63a8\u8350\u4f60\u770b\u770b\u5728XML-RPC\u4e2d\u4f7f\u7528\u7684 SimpleXMLRPCServer \u548c ServerProxy \u7684\u5b9e\u73b0\uff0c\n\u4e5f\u5c31\u662f11.6\u5c0f\u8282\u4e2d\u7684\u5185\u5bb9\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.9 \u7b80\u5355\u7684\u5ba2\u6237\u7aef\u8ba4\u8bc1\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5728\u5206\u5e03\u5f0f\u7cfb\u7edf\u4e2d\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u5ba2\u6237\u7aef\u8fde\u63a5\u8ba4\u8bc1\u529f\u80fd\uff0c\u53c8\u4e0d\u60f3\u50cfSSL\u90a3\u6837\u7684\u590d\u6742\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u53ef\u4ee5\u5229\u7528 hmac \u6a21\u5757\u5b9e\u73b0\u4e00\u4e2a\u8fde\u63a5\u63e1\u624b\uff0c\u4ece\u800c\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u800c\u9ad8\u6548\u7684\u8ba4\u8bc1\u8fc7\u7a0b\u3002\u4e0b\u9762\u662f\u4ee3\u7801\u793a\u4f8b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import hmac\nimport os\n\ndef client_authenticate(connection, secret_key):\n    '''\n    Authenticate client to a remote service.\n    connection represents a network connection.\n    secret_key is a key known only to both client/server.\n    '''\n    message = connection.recv(32)\n    hash = hmac.new(secret_key, message)\n    digest = hash.digest()\n    connection.send(digest)\n\ndef server_authenticate(connection, secret_key):\n    '''\n    Request client authentication.\n    '''\n    message = os.urandom(32)\n    connection.send(message)\n    hash = hmac.new(secret_key, message)\n    digest = hash.digest()\n    response = connection.recv(len(digest))\n    return hmac.compare_digest(digest,response)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u57fa\u672c\u539f\u7406\u662f\u5f53\u8fde\u63a5\u5efa\u7acb\u540e\uff0c\u670d\u52a1\u5668\u7ed9\u5ba2\u6237\u7aef\u53d1\u9001\u4e00\u4e2a\u968f\u673a\u7684\u5b57\u8282\u6d88\u606f\uff08\u8fd9\u91cc\u4f8b\u5b50\u4e2d\u4f7f\u7528\u4e86 os.urandom() \u8fd4\u56de\u503c\uff09\u3002\n\u5ba2\u6237\u7aef\u548c\u670d\u52a1\u5668\u540c\u65f6\u5229\u7528hmac\u548c\u4e00\u4e2a\u53ea\u6709\u53cc\u65b9\u77e5\u9053\u7684\u5bc6\u94a5\u6765\u8ba1\u7b97\u51fa\u4e00\u4e2a\u52a0\u5bc6\u54c8\u5e0c\u503c\u3002\u7136\u540e\u5ba2\u6237\u7aef\u5c06\u5b83\u8ba1\u7b97\u51fa\u7684\u6458\u8981\u53d1\u9001\u7ed9\u670d\u52a1\u5668\uff0c\n\u670d\u52a1\u5668\u901a\u8fc7\u6bd4\u8f83\u8fd9\u4e2a\u503c\u548c\u81ea\u5df1\u8ba1\u7b97\u7684\u662f\u5426\u4e00\u81f4\u6765\u51b3\u5b9a\u63a5\u53d7\u6216\u62d2\u7edd\u8fde\u63a5\u3002\u6458\u8981\u7684\u6bd4\u8f83\u9700\u8981\u4f7f\u7528 hmac.compare_digest() \u51fd\u6570\u3002\n\u4f7f\u7528\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u907f\u514d\u906d\u5230\u65f6\u95f4\u5206\u6790\u653b\u51fb\uff0c\u4e0d\u8981\u7528\u7b80\u5355\u7684\u6bd4\u8f83\u64cd\u4f5c\u7b26\uff08==\uff09\u3002\n\u4e3a\u4e86\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\uff0c\u4f60\u9700\u8981\u5c06\u5b83\u96c6\u6210\u5230\u5df2\u6709\u7684\u7f51\u7edc\u6216\u6d88\u606f\u4ee3\u7801\u4e2d\u3002\u4f8b\u5982\uff0c\u5bf9\u4e8esockets\uff0c\u670d\u52a1\u5668\u4ee3\u7801\u5e94\u8be5\u7c7b\u4f3c\u4e0b\u9762\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\n\nsecret_key = b'peekaboo'\ndef echo_handler(client_sock):\n    if not server_authenticate(client_sock, secret_key):\n        client_sock.close()\n        return\n    while True:\n\n        msg = client_sock.recv(8192)\n        if not msg:\n            break\n        client_sock.sendall(msg)\n\ndef echo_server(address):\n    s = socket(AF_INET, SOCK_STREAM)\n    s.bind(address)\n    s.listen(5)\n    while True:\n        c,a = s.accept()\n        echo_handler(c)\n\necho_server(('', 18000))\n\nWithin a client, you would do this:\n\nfrom socket import socket, AF_INET, SOCK_STREAM\n\nsecret_key = b'peekaboo'\n\ns = socket(AF_INET, SOCK_STREAM)\ns.connect(('localhost', 18000))\nclient_authenticate(s, secret_key)\ns.send(b'Hello World')\nresp = s.recv(1024)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "hmac \u8ba4\u8bc1\u7684\u4e00\u4e2a\u5e38\u89c1\u4f7f\u7528\u573a\u666f\u662f\u5185\u90e8\u6d88\u606f\u901a\u4fe1\u7cfb\u7edf\u548c\u8fdb\u7a0b\u95f4\u901a\u4fe1\u3002\n\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u7f16\u5199\u7684\u7cfb\u7edf\u6d89\u53ca\u5230\u4e00\u4e2a\u96c6\u7fa4\u4e2d\u591a\u4e2a\u5904\u7406\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff0c\n\u4f60\u53ef\u4ee5\u4f7f\u7528\u672c\u8282\u65b9\u6848\u6765\u786e\u4fdd\u53ea\u6709\u88ab\u5141\u8bb8\u7684\u8fdb\u7a0b\u4e4b\u95f4\u624d\u80fd\u5f7c\u6b64\u901a\u4fe1\u3002\n\u4e8b\u5b9e\u4e0a\uff0c\u57fa\u4e8e hmac \u7684\u8ba4\u8bc1\u88ab multiprocessing \u6a21\u5757\u4f7f\u7528\u6765\u5b9e\u73b0\u5b50\u8fdb\u7a0b\u76f4\u63a5\u7684\u901a\u4fe1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd8\u6709\u4e00\u70b9\u9700\u8981\u5f3a\u8c03\u7684\u662f\u8fde\u63a5\u8ba4\u8bc1\u548c\u52a0\u5bc6\u662f\u4e24\u7801\u4e8b\u3002\n\u8ba4\u8bc1\u6210\u529f\u4e4b\u540e\u7684\u901a\u4fe1\u6d88\u606f\u662f\u4ee5\u660e\u6587\u5f62\u5f0f\u53d1\u9001\u7684\uff0c\u4efb\u4f55\u4eba\u53ea\u8981\u60f3\u76d1\u542c\u8fd9\u4e2a\u8fde\u63a5\u7ebf\u8def\u90fd\u80fd\u770b\u5230\u6d88\u606f\uff08\u5c3d\u7ba1\u53cc\u65b9\u7684\u5bc6\u94a5\u4e0d\u4f1a\u88ab\u4f20\u8f93\uff09\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "hmac\u8ba4\u8bc1\u7b97\u6cd5\u57fa\u4e8e\u54c8\u5e0c\u51fd\u6570\u5982MD5\u548cSHA-1\uff0c\u5173\u4e8e\u8fd9\u4e2a\u5728IETF RFC 2104\u4e2d\u6709\u8be6\u7ec6\u4ecb\u7ecd\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.10 \u5728\u7f51\u7edc\u670d\u52a1\u4e2d\u52a0\u5165SSL\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u60f3\u5b9e\u73b0\u4e00\u4e2a\u57fa\u4e8esockets\u7684\u7f51\u7edc\u670d\u52a1\uff0c\u5ba2\u6237\u7aef\u548c\u670d\u52a1\u5668\u901a\u8fc7SSL\u534f\u8bae\u8ba4\u8bc1\u5e76\u52a0\u5bc6\u4f20\u8f93\u7684\u6570\u636e\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "ssl \u6a21\u5757\u80fd\u4e3a\u5e95\u5c42socket\u8fde\u63a5\u6dfb\u52a0SSL\u7684\u652f\u6301\u3002\nssl.wrap_socket() \u51fd\u6570\u63a5\u53d7\u4e00\u4e2a\u5df2\u5b58\u5728\u7684socket\u4f5c\u4e3a\u53c2\u6570\u5e76\u4f7f\u7528SSL\u5c42\u6765\u5305\u88c5\u5b83\u3002\n\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u5e94\u7b54\u670d\u52a1\u5668\uff0c\u80fd\u5728\u670d\u52a1\u5668\u7aef\u4e3a\u6240\u6709\u5ba2\u6237\u7aef\u8fde\u63a5\u505a\u8ba4\u8bc1\u3002"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\nimport ssl\n\nKEYFILE = 'server_key.pem'   # Private key of the server\nCERTFILE = 'server_cert.pem' # Server certificate (given to client)\n\ndef echo_client(s):\n    while True:\n        data = s.recv(8192)\n        if data == b'':\n            break\n        s.send(data)\n    s.close()\n    print('Connection closed')\n\ndef echo_server(address):\n    s = socket(AF_INET, SOCK_STREAM)\n    s.bind(address)\n    s.listen(1)\n\n    # Wrap with an SSL layer requiring client certs\n    s_ssl = ssl.wrap_socket(s,\n                            keyfile=KEYFILE,\n                            certfile=CERTFILE,\n                            server_side=True\n                            )\n    # Wait for connections\n    while True:\n        try:\n            c,a = s_ssl.accept()\n            print('Got connection', c, a)\n            echo_client(c)\n        except Exception as e:\n            print('{}: {}'.format(e.__class__.__name__, e))\n\necho_server(('', 20000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u6211\u4eec\u6f14\u793a\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u5668\u7684\u4ea4\u4e92\u4f8b\u5b50\u3002\u5ba2\u6237\u7aef\u4f1a\u8bf7\u6c42\u670d\u52a1\u5668\u6765\u8ba4\u8bc1\u5e76\u786e\u8ba4\u8fde\u63a5\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import socket, AF_INET, SOCK_STREAM\nimport ssl\ns = socket(AF_INET, SOCK_STREAM)\ns_ssl = ssl.wrap_socket(s,"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s_ssl.connect(('localhost', 20000))\ns_ssl.send(b'Hello World?')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s_ssl.recv(8192)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u79cd\u76f4\u63a5\u5904\u7406\u5e95\u5c42socket\u65b9\u5f0f\u6709\u4e2a\u95ee\u9898\u5c31\u662f\u5b83\u4e0d\u80fd\u5f88\u597d\u7684\u8ddf\u6807\u51c6\u5e93\u4e2d\u5df2\u5b58\u5728\u7684\u7f51\u7edc\u670d\u52a1\u517c\u5bb9\u3002\n\u4f8b\u5982\uff0c\u7edd\u5927\u90e8\u5206\u670d\u52a1\u5668\u4ee3\u7801\uff08HTTP\u3001XML-RPC\u7b49\uff09\u5b9e\u9645\u4e0a\u662f\u57fa\u4e8e socketserver \u5e93\u7684\u3002\n\u5ba2\u6237\u7aef\u4ee3\u7801\u5728\u4e00\u4e2a\u8f83\u9ad8\u5c42\u4e0a\u5b9e\u73b0\u3002\u6211\u4eec\u9700\u8981\u53e6\u5916\u4e00\u79cd\u7a0d\u5fae\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u5c06SSL\u6dfb\u52a0\u5230\u5df2\u5b58\u5728\u7684\u670d\u52a1\u4e2d\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u9996\u5148\uff0c\u5bf9\u4e8e\u670d\u52a1\u5668\u800c\u8a00\uff0c\u53ef\u4ee5\u901a\u8fc7\u50cf\u4e0b\u9762\u8fd9\u6837\u4f7f\u7528\u4e00\u4e2amixin\u7c7b\u6765\u6dfb\u52a0SSL\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import ssl\n\nclass SSLMixin:\n    '''\n    Mixin class that adds support for SSL to existing servers based\n    on the socketserver module.\n    '''\n    def __init__(self, *args,\n                 keyfile=None, certfile=None, ca_certs=None,\n                 cert_reqs=ssl.CERT_NONE,\n                 **kwargs):\n        self._keyfile = keyfile\n        self._certfile = certfile\n        self._ca_certs = ca_certs\n        self._cert_reqs = cert_reqs\n        super().__init__(*args, **kwargs)\n\n    def get_request(self):\n        client, addr = super().get_request()\n        client_ssl = ssl.wrap_socket(client,\n                                     keyfile = self._keyfile,\n                                     certfile = self._certfile,\n                                     ca_certs = self._ca_certs,\n                                     cert_reqs = self._cert_reqs,\n                                     server_side = True)\n        return client_ssl, addr"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u4f7f\u7528\u8fd9\u4e2amixin\u7c7b\uff0c\u4f60\u53ef\u4ee5\u5c06\u5b83\u8ddf\u5176\u4ed6\u670d\u52a1\u5668\u7c7b\u6df7\u5408\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u5b9a\u4e49\u4e00\u4e2a\u57fa\u4e8eSSL\u7684XML-RPC\u670d\u52a1\u5668\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# XML-RPC server with SSL\n\nfrom xmlrpc.server import SimpleXMLRPCServer\n\nclass SSLSimpleXMLRPCServer(SSLMixin, SimpleXMLRPCServer):\n    pass\n\nHere's the XML-RPC server from Recipe 11.6 modified only slightly to use SSL:\n\nimport ssl\nfrom xmlrpc.server import SimpleXMLRPCServer\nfrom sslmixin import SSLMixin\n\nclass SSLSimpleXMLRPCServer(SSLMixin, SimpleXMLRPCServer):\n    pass\n\nclass KeyValueServer:\n    _rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']\n    def __init__(self, *args, **kwargs):\n        self._data = {}\n        self._serv = SSLSimpleXMLRPCServer(*args, allow_none=True, **kwargs)\n        for name in self._rpc_methods_:\n            self._serv.register_function(getattr(self, name))\n\n    def get(self, name):\n        return self._data[name]\n\n    def set(self, name, value):\n        self._data[name] = value\n\n    def delete(self, name):\n        del self._data[name]\n\n    def exists(self, name):\n        return name in self._data\n\n    def keys(self):\n        return list(self._data)\n\n    def serve_forever(self):\n        self._serv.serve_forever()\n\nif __name__ == '__main__':\n    KEYFILE='server_key.pem'    # Private key of the server\n    CERTFILE='server_cert.pem'  # Server certificate\n    kvserv = KeyValueServer(('', 15000),\n                            keyfile=KEYFILE,\n                            certfile=CERTFILE)\n    kvserv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f7f\u7528\u8fd9\u4e2a\u670d\u52a1\u5668\u65f6\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u666e\u901a\u7684 xmlrpc.client \u6a21\u5757\u6765\u8fde\u63a5\u5b83\u3002\n\u53ea\u9700\u8981\u5728URL\u4e2d\u6307\u5b9a https: \u5373\u53ef\uff0c\u4f8b\u5982\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from xmlrpc.client import ServerProxy\ns = ServerProxy('https://localhost:15000', allow_none=True)\ns.set('foo','bar')\ns.set('spam', [1, 2, 3])\ns.keys()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.get('foo')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.get('spam')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.delete('spam')\ns.exists('spam')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8eSSL\u5ba2\u6237\u7aef\u6765\u8bb2\u4e00\u4e2a\u6bd4\u8f83\u590d\u6742\u7684\u95ee\u9898\u662f\u5982\u4f55\u786e\u8ba4\u670d\u52a1\u5668\u8bc1\u4e66\u6216\u4e3a\u670d\u52a1\u5668\u63d0\u4f9b\u5ba2\u6237\u7aef\u8ba4\u8bc1\uff08\u6bd4\u5982\u5ba2\u6237\u7aef\u8bc1\u4e66\uff09\u3002\n\u4e0d\u5e78\u7684\u662f\uff0c\u6682\u65f6\u8fd8\u6ca1\u6709\u4e00\u4e2a\u6807\u51c6\u65b9\u6cd5\u6765\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u9700\u8981\u81ea\u5df1\u53bb\u7814\u7a76\u3002\n\u4e0d\u8fc7\uff0c\u4e0b\u9762\u7ed9\u51fa\u4e00\u4e2a\u4f8b\u5b50\uff0c\u7528\u6765\u5efa\u7acb\u4e00\u4e2a\u5b89\u5168\u7684XML-RPC\u8fde\u63a5\u6765\u786e\u8ba4\u670d\u52a1\u5668\u8bc1\u4e66\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from xmlrpc.client import SafeTransport, ServerProxy\nimport ssl\n\nclass VerifyCertSafeTransport(SafeTransport):\n    def __init__(self, cafile, certfile=None, keyfile=None):\n        SafeTransport.__init__(self)\n        self._ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)\n        self._ssl_context.load_verify_locations(cafile)\n        if certfile:\n            self._ssl_context.load_cert_chain(certfile, keyfile)\n        self._ssl_context.verify_mode = ssl.CERT_REQUIRED\n\n    def make_connection(self, host):\n        # Items in the passed dictionary are passed as keyword\n        # arguments to the http.client.HTTPSConnection() constructor.\n        # The context argument allows an ssl.SSLContext instance to\n        # be passed with information about the SSL configuration\n        s = super().make_connection((host, {'context': self._ssl_context}))\n\n        return s\n\n# Create the client proxy\ns = ServerProxy('https://localhost:15000',\n                transport=VerifyCertSafeTransport('server_cert.pem'),\n                allow_none=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u670d\u52a1\u5668\u5c06\u8bc1\u4e66\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u6765\u786e\u8ba4\u5b83\u7684\u5408\u6cd5\u6027\u3002\u8fd9\u79cd\u786e\u8ba4\u53ef\u4ee5\u662f\u76f8\u4e92\u7684\u3002\n\u5982\u679c\u670d\u52a1\u5668\u60f3\u8981\u786e\u8ba4\u5ba2\u6237\u7aef\uff0c\u53ef\u4ee5\u5c06\u670d\u52a1\u5668\u542f\u52a8\u4ee3\u7801\u4fee\u6539\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "if __name__ == '__main__':\n    KEYFILE='server_key.pem'   # Private key of the server\n    CERTFILE='server_cert.pem' # Server certificate\n    CA_CERTS='client_cert.pem' # Certificates of accepted clients\n\n    kvserv = KeyValueServer(('', 15000),\n                            keyfile=KEYFILE,\n                            certfile=CERTFILE,\n                            ca_certs=CA_CERTS,\n                            cert_reqs=ssl.CERT_REQUIRED,\n                            )\n    kvserv.serve_forever()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u8ba9XML-RPC\u5ba2\u6237\u7aef\u53d1\u9001\u8bc1\u4e66\uff0c\u4fee\u6539 ServerProxy \u7684\u521d\u59cb\u5316\u4ee3\u7801\u5982\u4e0b\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Create the client proxy\ns = ServerProxy('https://localhost:15000',\n                transport=VerifyCertSafeTransport('server_cert.pem',\n                                                  'client_cert.pem',\n                                                  'client_key.pem'),\n                allow_none=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8bd5\u7740\u53bb\u8fd0\u884c\u672c\u8282\u7684\u4ee3\u7801\u80fd\u6d4b\u8bd5\u4f60\u7684\u7cfb\u7edf\u914d\u7f6e\u80fd\u529b\u548c\u7406\u89e3SSL\u3002\n\u53ef\u80fd\u6700\u5927\u7684\u6311\u6218\u662f\u5982\u4f55\u4e00\u6b65\u6b65\u7684\u83b7\u53d6\u521d\u59cb\u914d\u7f6ekey\u3001\u8bc1\u4e66\u548c\u5176\u4ed6\u6240\u9700\u4f9d\u8d56\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6211\u89e3\u91ca\u4e0b\u5230\u5e95\u9700\u8981\u5565\uff0c\u6bcf\u4e00\u4e2aSSL\u8fde\u63a5\u7ec8\u7aef\u4e00\u822c\u90fd\u4f1a\u6709\u4e00\u4e2a\u79c1\u94a5\u548c\u4e00\u4e2a\u7b7e\u540d\u8bc1\u4e66\u6587\u4ef6\u3002\n\u8fd9\u4e2a\u8bc1\u4e66\u5305\u542b\u4e86\u516c\u94a5\u5e76\u5728\u6bcf\u4e00\u6b21\u8fde\u63a5\u7684\u65f6\u5019\u90fd\u4f1a\u53d1\u9001\u7ed9\u5bf9\u65b9\u3002\n\u5bf9\u4e8e\u516c\u5171\u670d\u52a1\u5668\uff0c\u5b83\u4eec\u7684\u8bc1\u4e66\u901a\u5e38\u662f\u88ab\u6743\u5a01\u8bc1\u4e66\u673a\u6784\u6bd4\u5982Verisign\u3001Equifax\u6216\u5176\u4ed6\u7c7b\u4f3c\u673a\u6784\uff08\u9700\u8981\u4ed8\u8d39\u7684\uff09\u7b7e\u540d\u8fc7\u7684\u3002\n\u4e3a\u4e86\u786e\u8ba4\u670d\u52a1\u5668\u7b7e\u540d\uff0c\u5ba2\u6237\u7aef\u56de\u4fdd\u5b58\u4e00\u4efd\u5305\u542b\u4e86\u4fe1\u4efb\u6388\u6743\u673a\u6784\u7684\u8bc1\u4e66\u5217\u8868\u6587\u4ef6\u3002\n\u4f8b\u5982\uff0cweb\u6d4f\u89c8\u5668\u4fdd\u5b58\u4e86\u4e3b\u8981\u7684\u8ba4\u8bc1\u673a\u6784\u7684\u8bc1\u4e66\uff0c\u5e76\u4f7f\u7528\u5b83\u6765\u4e3a\u6bcf\u4e00\u4e2aHTTPS\u8fde\u63a5\u786e\u8ba4\u8bc1\u4e66\u7684\u5408\u6cd5\u6027\u3002\n\u5bf9\u672c\u5c0f\u8282\u793a\u4f8b\u800c\u8a00\uff0c\u53ea\u662f\u4e3a\u4e86\u6d4b\u8bd5\uff0c\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u81ea\u7b7e\u540d\u7684\u8bc1\u4e66\uff0c\u4e0b\u9762\u662f\u4e3b\u8981\u6b65\u9aa4\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Generating a 1024 bit RSA private key\n\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026++++++\n\u2026++++++"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "writing new private key to \u2018server_key.pem\u2019"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "You are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields but you can leave some blank\nFor some fields there will be a default value,\nIf you enter \u2018.\u2019, the field will be left blank."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Country Name (2 letter code) [AU]:US\nState or Province Name (full name) [Some-State]:Illinois\nLocality Name (eg, city) []:Chicago\nOrganization Name (eg, company) [Internet Widgits Pty Ltd]:Dabeaz, LLC\nOrganizational Unit Name (eg, section) []:\nCommon Name (eg, YOUR name) []:localhost\nEmail Address []:\nbash %"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u521b\u5efa\u8bc1\u4e66\u7684\u65f6\u5019\uff0c\u5404\u4e2a\u503c\u7684\u8bbe\u5b9a\u53ef\u4ee5\u662f\u4efb\u610f\u7684\uff0c\u4f46\u662f\u201dCommon Name\u201c\u7684\u503c\u901a\u5e38\u8981\u5305\u542b\u670d\u52a1\u5668\u7684DNS\u4e3b\u673a\u540d\u3002\n\u5982\u679c\u4f60\u53ea\u662f\u5728\u672c\u673a\u6d4b\u8bd5\uff0c\u90a3\u4e48\u5c31\u4f7f\u7528\u201dlocalhost\u201c\uff0c\u5426\u5219\u4f7f\u7528\u670d\u52a1\u5668\u7684\u57df\u540d\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u670d\u52a1\u5668\u8bc1\u4e66\u6587\u4ef6server_cert.pem\u5185\u5bb9\u7c7b\u4f3c\u4e0b\u9762\u8fd9\u6837\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u2014\u2013BEGIN CERTIFICATE\u2014\u2013\nMIIC+DCCAmGgAwIBAgIJAPMd+vi45js3MA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV\nBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2FnbzEUMBIG\nA1UEChMLRGFiZWF6LCBMTEMxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMzAxMTEx\nODQyMjdaFw0xNDAxMTExODQyMjdaMFwxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJ\nbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2FnbzEUMBIGA1UEChMLRGFiZWF6LCBMTEMx\nEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\nmawjS6BMgChfn/VDXBWs+TrGuo3+6pG1JfLIucUK2N2WAu47rpy9XWS5/1WxBSCE\n2lDoLwbT79alFkyRsIGutlUhtaBRNDgyMd4NjYeLEX/q8krMdi+OONp8dM+DubyU"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "O5OnkTRwGVFJwi+dPmL48i8re68i0o0rioQnCbG2YD8CAwEAAaOBwTCBvjAdBgNV\nHQ4EFgQUrtoLHHgXiDZTr26NMmgKJLJLFtIwgY4GA1UdIwSBhjCBg4AUrtoLHHgX\niDZTr26NMmgKJLJLFtKhYKReMFwxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxp\nbm9pczEQMA4GA1UEBxMHQ2hpY2FnbzEUMBIGA1UEChMLRGFiZWF6LCBMTEMxEjAQ\nBgNVBAMTCWxvY2FsaG9zdIIJAPMd+vi45js3MAwGA1UdEwQFMAMBAf8wDQYJKoZI\nhvcNAQEFBQADgYEAFci+dqvMG4xF8UTnbGVvZJPIzJDRee6Nbt6AHQo9pOdAIMAu\nWsGCplSOaDNdKKzl+b2UT2Zp3AIW4Qd51bouSNnR4M/gnr9ZD1ZctFd3jS+C5XRp\nD3vvcW5lAnCCC80P6rXy7d7hTeFu5EYKtRGXNvVNd/06NALGDflrrOwxF3Y=\n\u2014\u2013END CERTIFICATE\u2014\u2013"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u670d\u52a1\u5668\u7aef\u4ee3\u7801\u4e2d\uff0c\u79c1\u94a5\u548c\u8bc1\u4e66\u6587\u4ef6\u4f1a\u88ab\u4f20\u7ed9SSL\u76f8\u5173\u7684\u5305\u88c5\u51fd\u6570\u3002\u8bc1\u4e66\u6765\u81ea\u4e8e\u5ba2\u6237\u7aef\uff0c\n\u79c1\u94a5\u5e94\u8be5\u5728\u4fdd\u5b58\u5728\u670d\u52a1\u5668\u4e2d\uff0c\u5e76\u52a0\u4ee5\u5b89\u5168\u4fdd\u62a4\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u5ba2\u6237\u7aef\u4ee3\u7801\u4e2d\uff0c\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u5408\u6cd5\u8bc1\u4e66\u6388\u6743\u6587\u4ef6\u6765\u786e\u8ba4\u670d\u52a1\u5668\u8bc1\u4e66\u3002\n\u5982\u679c\u4f60\u6ca1\u6709\u8fd9\u4e2a\u6587\u4ef6\uff0c\u4f60\u53ef\u4ee5\u5728\u5ba2\u6237\u7aef\u590d\u5236\u4e00\u4efd\u670d\u52a1\u5668\u7684\u8bc1\u4e66\u5e76\u4f7f\u7528\u5b83\u6765\u786e\u8ba4\u3002\n\u8fde\u63a5\u5efa\u7acb\u540e\uff0c\u670d\u52a1\u5668\u4f1a\u63d0\u4f9b\u5b83\u7684\u8bc1\u4e66\uff0c\u7136\u540e\u4f60\u5c31\u80fd\u4f7f\u7528\u5df2\u7ecf\u4fdd\u5b58\u7684\u8bc1\u4e66\u6765\u786e\u8ba4\u5b83\u662f\u5426\u6b63\u786e\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u670d\u52a1\u5668\u4e5f\u80fd\u9009\u62e9\u662f\u5426\u8981\u786e\u8ba4\u5ba2\u6237\u7aef\u7684\u8eab\u4efd\u3002\u5982\u679c\u8981\u8fd9\u6837\u505a\u7684\u8bdd\uff0c\u5ba2\u6237\u7aef\u9700\u8981\u6709\u81ea\u5df1\u7684\u79c1\u94a5\u548c\u8ba4\u8bc1\u6587\u4ef6\u3002\n\u670d\u52a1\u5668\u4e5f\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u88ab\u4fe1\u4efb\u8bc1\u4e66\u6388\u6743\u6587\u4ef6\u6765\u786e\u8ba4\u5ba2\u6237\u7aef\u8bc1\u4e66\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u8981\u5728\u771f\u5b9e\u73af\u5883\u4e2d\u4e3a\u4f60\u7684\u7f51\u7edc\u670d\u52a1\u52a0\u4e0aSSL\u7684\u652f\u6301\uff0c\u8fd9\u5c0f\u8282\u53ea\u662f\u4e00\u4e2a\u5165\u95e8\u4ecb\u7ecd\u800c\u5df2\u3002\n\u4f60\u8fd8\u5e94\u8be5\u53c2\u8003\u5176\u4ed6\u7684\u6587\u6863\uff0c\u505a\u597d\u82b1\u8d39\u4e0d\u5c11\u65f6\u95f4\u6765\u6d4b\u8bd5\u5b83\u6b63\u5e38\u5de5\u4f5c\u7684\u51c6\u5907\u3002\u53cd\u6b63\uff0c\u5c31\u662f\u5f97\u6162\u6162\u6298\u817e\u5427~ ^_^"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.11 \u8fdb\u7a0b\u95f4\u4f20\u9012Socket\u6587\u4ef6\u63cf\u8ff0\u7b26\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u6709\u591a\u4e2aPython\u89e3\u91ca\u5668\u8fdb\u7a0b\u5728\u540c\u65f6\u8fd0\u884c\uff0c\u4f60\u60f3\u5c06\u67d0\u4e2a\u6253\u5f00\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u4ece\u4e00\u4e2a\u89e3\u91ca\u5668\u4f20\u9012\u7ed9\u53e6\u5916\u4e00\u4e2a\u3002\n\u6bd4\u5982\uff0c\u5047\u8bbe\u6709\u4e2a\u670d\u52a1\u5668\u8fdb\u7a0b\u76f8\u5e94\u8fde\u63a5\u8bf7\u6c42\uff0c\u4f46\u662f\u5b9e\u9645\u7684\u76f8\u5e94\u903b\u8f91\u662f\u5728\u53e6\u4e00\u4e2a\u89e3\u91ca\u5668\u4e2d\u6267\u884c\u7684\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u5728\u591a\u4e2a\u8fdb\u7a0b\u4e2d\u4f20\u9012\u6587\u4ef6\u63cf\u8ff0\u7b26\uff0c\u4f60\u9996\u5148\u9700\u8981\u5c06\u5b83\u4eec\u8fde\u63a5\u5230\u4e00\u8d77\u3002\u5728Unix\u673a\u5668\u4e0a\uff0c\u4f60\u53ef\u80fd\u9700\u8981\u4f7f\u7528Unix\u57df\u5957\u63a5\u5b57\uff0c\n\u800c\u5728windows\u4e0a\u9762\u4f60\u9700\u8981\u4f7f\u7528\u547d\u540d\u7ba1\u9053\u3002\u4e0d\u8fc7\u4f60\u65e0\u9700\u771f\u7684\u9700\u8981\u53bb\u64cd\u4f5c\u8fd9\u4e9b\u5e95\u5c42\uff0c\n\u901a\u5e38\u4f7f\u7528 multiprocessing \u6a21\u5757\u6765\u521b\u5efa\u8fd9\u6837\u7684\u8fde\u63a5\u4f1a\u66f4\u5bb9\u6613\u4e00\u4e9b\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u65e6\u4e00\u4e2a\u8fde\u63a5\u88ab\u521b\u5efa\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 multiprocessing.reduction \u4e2d\u7684\nsend_handle() \u548c recv_handle() \u51fd\u6570\u5728\u4e0d\u540c\u7684\u5904\u7406\u5668\u76f4\u63a5\u4f20\u9012\u6587\u4ef6\u63cf\u8ff0\u7b26\u3002\n\u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u6700\u57fa\u672c\u7684\u7528\u6cd5\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import multiprocessing\nfrom multiprocessing.reduction import recv_handle, send_handle\nimport socket\n\ndef worker(in_p, out_p):\n    out_p.close()\n    while True:\n        fd = recv_handle(in_p)\n        print('CHILD: GOT FD', fd)\n        with socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=fd) as s:\n            while True:\n                msg = s.recv(1024)\n                if not msg:\n                    break\n                print('CHILD: RECV {!r}'.format(msg))\n                s.send(msg)\n\ndef server(address, in_p, out_p, worker_pid):\n    in_p.close()\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)\n    s.bind(address)\n    s.listen(1)\n    while True:\n        client, addr = s.accept()\n        print('SERVER: Got connection from', addr)\n        send_handle(out_p, client.fileno(), worker_pid)\n        client.close()\n\nif __name__ == '__main__':\n    c1, c2 = multiprocessing.Pipe()\n    worker_p = multiprocessing.Process(target=worker, args=(c1,c2))\n    worker_p.start()\n\n    server_p = multiprocessing.Process(target=server,\n                  args=(('', 15000), c1, c2, worker_p.pid))\n    server_p.start()\n\n    c1.close()\n    c2.close()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8fdb\u7a0b\u88ab\u521b\u5efa\u5e76\u901a\u8fc7\u4e00\u4e2a multiprocessing \u7ba1\u9053\u8fde\u63a5\u8d77\u6765\u3002\n\u670d\u52a1\u5668\u8fdb\u7a0b\u6253\u5f00\u4e00\u4e2asocket\u5e76\u7b49\u5f85\u5ba2\u6237\u7aef\u8fde\u63a5\u8bf7\u6c42\u3002\n\u5de5\u4f5c\u8fdb\u7a0b\u4ec5\u4ec5\u4f7f\u7528 recv_handle() \u5728\u7ba1\u9053\u4e0a\u9762\u7b49\u5f85\u63a5\u6536\u4e00\u4e2a\u6587\u4ef6\u63cf\u8ff0\u7b26\u3002\n\u5f53\u670d\u52a1\u5668\u63a5\u6536\u5230\u4e00\u4e2a\u8fde\u63a5\uff0c\u5b83\u5c06\u4ea7\u751f\u7684socket\u6587\u4ef6\u63cf\u8ff0\u7b26\u901a\u8fc7 send_handle() \u4f20\u9012\u7ed9\u5de5\u4f5c\u8fdb\u7a0b\u3002\n\u5de5\u4f5c\u8fdb\u7a0b\u63a5\u6536\u5230socket\u540e\u5411\u5ba2\u6237\u7aef\u56de\u5e94\u6570\u636e\uff0c\u7136\u540e\u6b64\u6b21\u8fde\u63a5\u5173\u95ed\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u4f7f\u7528Telnet\u6216\u7c7b\u4f3c\u5de5\u5177\u8fde\u63a5\u5230\u670d\u52a1\u5668\uff0c\u4e0b\u9762\u662f\u4e00\u4e2a\u6f14\u793a\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6b64\u4f8b\u6700\u91cd\u8981\u7684\u90e8\u5206\u662f\u670d\u52a1\u5668\u63a5\u6536\u5230\u7684\u5ba2\u6237\u7aefsocket\u5b9e\u9645\u4e0a\u88ab\u53e6\u5916\u4e00\u4e2a\u4e0d\u540c\u7684\u8fdb\u7a0b\u5904\u7406\u3002\n\u670d\u52a1\u5668\u4ec5\u4ec5\u53ea\u662f\u5c06\u5176\u8f6c\u624b\u5e76\u5173\u95ed\u6b64\u8fde\u63a5\uff0c\u7136\u540e\u7b49\u5f85\u4e0b\u4e00\u4e2a\u8fde\u63a5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u5927\u90e8\u5206\u7a0b\u5e8f\u5458\u6765\u8bb2\u5728\u4e0d\u540c\u8fdb\u7a0b\u4e4b\u95f4\u4f20\u9012\u6587\u4ef6\u63cf\u8ff0\u7b26\u597d\u50cf\u6ca1\u4ec0\u4e48\u5fc5\u8981\u3002\n\u4f46\u662f\uff0c\u6709\u65f6\u5019\u5b83\u662f\u6784\u5efa\u4e00\u4e2a\u53ef\u6269\u5c55\u7cfb\u7edf\u7684\u5f88\u6709\u7528\u7684\u5de5\u5177\u3002\u4f8b\u5982\uff0c\u5728\u4e00\u4e2a\u591a\u6838\u673a\u5668\u4e0a\u9762\uff0c\n\u4f60\u53ef\u4ee5\u6709\u591a\u4e2aPython\u89e3\u91ca\u5668\u5b9e\u4f8b\uff0c\u5c06\u6587\u4ef6\u63cf\u8ff0\u7b26\u4f20\u9012\u7ed9\u5176\u5b83\u89e3\u91ca\u5668\u6765\u5b9e\u73b0\u8d1f\u8f7d\u5747\u8861\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "send_handle() \u548c recv_handle() \u51fd\u6570\u53ea\u80fd\u591f\u7528\u4e8e multiprocessing \u8fde\u63a5\u3002\n\u4f7f\u7528\u5b83\u4eec\u6765\u4ee3\u66ff\u7ba1\u9053\u7684\u4f7f\u7528\uff08\u53c2\u800311.7\u8282\uff09\uff0c\u53ea\u8981\u4f60\u4f7f\u7528\u7684\u662fUnix\u57df\u5957\u63a5\u5b57\u6216Windows\u7ba1\u9053\u3002\n\u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u8ba9\u670d\u52a1\u5668\u548c\u5de5\u4f5c\u8005\u5404\u81ea\u4ee5\u5355\u72ec\u7684\u7a0b\u5e8f\u6765\u542f\u52a8\u3002\u4e0b\u9762\u662f\u670d\u52a1\u5668\u7684\u5b9e\u73b0\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# servermp.py\nfrom multiprocessing.connection import Listener\nfrom multiprocessing.reduction import send_handle\nimport socket\n\ndef server(work_address, port):\n    # Wait for the worker to connect\n    work_serv = Listener(work_address, authkey=b'peekaboo')\n    worker = work_serv.accept()\n    worker_pid = worker.recv()\n\n    # Now run a TCP/IP server and send clients to worker\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)\n    s.bind(('', port))\n    s.listen(1)\n    while True:\n        client, addr = s.accept()\n        print('SERVER: Got connection from', addr)\n\n        send_handle(worker, client.fileno(), worker_pid)\n        client.close()\n\nif __name__ == '__main__':\n    import sys\n    if len(sys.argv) != 3:\n        print('Usage: server.py server_address port', file=sys.stderr)\n        raise SystemExit(1)\n\n    server(sys.argv[1], int(sys.argv[2]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd0\u884c\u8fd9\u4e2a\u670d\u52a1\u5668\uff0c\u53ea\u9700\u8981\u6267\u884c python3 servermp.py /tmp/servconn 15000 \uff0c\u4e0b\u9762\u662f\u76f8\u5e94\u7684\u5de5\u4f5c\u8005\u4ee3\u7801\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# workermp.py\n\nfrom multiprocessing.connection import Client\nfrom multiprocessing.reduction import recv_handle\nimport os\nfrom socket import socket, AF_INET, SOCK_STREAM\n\ndef worker(server_address):\n    serv = Client(server_address, authkey=b'peekaboo')\n    serv.send(os.getpid())\n    while True:\n        fd = recv_handle(serv)\n        print('WORKER: GOT FD', fd)\n        with socket(AF_INET, SOCK_STREAM, fileno=fd) as client:\n            while True:\n                msg = client.recv(1024)\n                if not msg:\n                    break\n                print('WORKER: RECV {!r}'.format(msg))\n                client.send(msg)\n\nif __name__ == '__main__':\n    import sys\n    if len(sys.argv) != 2:\n        print('Usage: worker.py server_address', file=sys.stderr)\n        raise SystemExit(1)\n\n    worker(sys.argv[1])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8981\u8fd0\u884c\u5de5\u4f5c\u8005\uff0c\u6267\u884c\u6267\u884c\u547d\u4ee4 python3 workermp.py /tmp/servconn .\n\u6548\u679c\u8ddf\u4f7f\u7528Pipe()\u4f8b\u5b50\u662f\u5b8c\u5168\u4e00\u6837\u7684\u3002\n\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u4f20\u9012\u4f1a\u6d89\u53ca\u5230UNIX\u57df\u5957\u63a5\u5b57\u7684\u521b\u5efa\u548c\u5957\u63a5\u5b57\u7684 sendmsg() \u65b9\u6cd5\u3002\n\u4e0d\u8fc7\u8fd9\u79cd\u6280\u672f\u5e76\u4e0d\u5e38\u89c1\uff0c\u4e0b\u9762\u662f\u4f7f\u7528\u5957\u63a5\u5b57\u6765\u4f20\u9012\u63cf\u8ff0\u7b26\u7684\u53e6\u5916\u4e00\u79cd\u5b9e\u73b0\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# server.py\nimport socket\n\nimport struct\n\ndef send_fd(sock, fd):\n    '''\n    Send a single file descriptor.\n    '''\n    sock.sendmsg([b'x'],\n                 [(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack('i', fd))])\n    ack = sock.recv(2)\n    assert ack == b'OK'\n\ndef server(work_address, port):\n    # Wait for the worker to connect\n    work_serv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n    work_serv.bind(work_address)\n    work_serv.listen(1)\n    worker, addr = work_serv.accept()\n\n    # Now run a TCP/IP server and send clients to worker\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)\n    s.bind(('',port))\n    s.listen(1)\n    while True:\n        client, addr = s.accept()\n        print('SERVER: Got connection from', addr)\n        send_fd(worker, client.fileno())\n        client.close()\n\nif __name__ == '__main__':\n    import sys\n    if len(sys.argv) != 3:\n        print('Usage: server.py server_address port', file=sys.stderr)\n        raise SystemExit(1)\n\n    server(sys.argv[1], int(sys.argv[2]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u662f\u4f7f\u7528\u5957\u63a5\u5b57\u7684\u5de5\u4f5c\u8005\u5b9e\u73b0\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# worker.py\nimport socket\nimport struct\n\ndef recv_fd(sock):\n    '''\n    Receive a single file descriptor\n    '''\n    msg, ancdata, flags, addr = sock.recvmsg(1,\n                                     socket.CMSG_LEN(struct.calcsize('i')))\n\n    cmsg_level, cmsg_type, cmsg_data = ancdata[0]\n    assert cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS\n    sock.sendall(b'OK')\n\n    return struct.unpack('i', cmsg_data)[0]\n\ndef worker(server_address):\n    serv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n    serv.connect(server_address)\n    while True:\n        fd = recv_fd(serv)\n        print('WORKER: GOT FD', fd)\n        with socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=fd) as client:\n            while True:\n                msg = client.recv(1024)\n                if not msg:\n                    break\n                print('WORKER: RECV {!r}'.format(msg))\n                client.send(msg)\n\nif __name__ == '__main__':\n    import sys\n    if len(sys.argv) != 2:\n        print('Usage: worker.py server_address', file=sys.stderr)\n        raise SystemExit(1)\n\n    worker(sys.argv[1])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5982\u679c\u4f60\u60f3\u5728\u4f60\u7684\u7a0b\u5e8f\u4e2d\u4f20\u9012\u6587\u4ef6\u63cf\u8ff0\u7b26\uff0c\u5efa\u8bae\u4f60\u53c2\u9605\u5176\u4ed6\u4e00\u4e9b\u66f4\u52a0\u9ad8\u7ea7\u7684\u6587\u6863\uff0c\n\u6bd4\u5982 Unix Network Programming by W. Richard Stevens\u00a0 (Prentice\u00a0 Hall,\u00a0 1990) .\n\u5728Windows\u4e0a\u4f20\u9012\u6587\u4ef6\u63cf\u8ff0\u7b26\u8ddfUnix\u662f\u4e0d\u4e00\u6837\u7684\uff0c\u5efa\u8bae\u4f60\u7814\u7a76\u4e0b multiprocessing.reduction \u4e2d\u7684\u6e90\u4ee3\u7801\u770b\u770b\u5176\u5de5\u4f5c\u539f\u7406\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.12 \u7406\u89e3\u4e8b\u4ef6\u9a71\u52a8\u7684IO\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5e94\u8be5\u5df2\u7ecf\u542c\u8fc7\u57fa\u4e8e\u4e8b\u4ef6\u9a71\u52a8\u6216\u5f02\u6b65I/O\u7684\u5305\uff0c\u4f46\u662f\u4f60\u8fd8\u4e0d\u80fd\u5b8c\u5168\u7406\u89e3\u5b83\u7684\u5e95\u5c42\u5230\u5e95\u662f\u600e\u6837\u5de5\u4f5c\u7684\uff0c\n\u6216\u8005\u662f\u5982\u679c\u4f7f\u7528\u5b83\u7684\u8bdd\u4f1a\u5bf9\u4f60\u7684\u7a0b\u5e8f\u4ea7\u751f\u4ec0\u4e48\u5f71\u54cd\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e8b\u4ef6\u9a71\u52a8I/O\u672c\u8d28\u4e0a\u6765\u8bb2\u5c31\u662f\u5c06\u57fa\u672cI/O\u64cd\u4f5c\uff08\u6bd4\u5982\u8bfb\u548c\u5199\uff09\u8f6c\u5316\u4e3a\u4f60\u7a0b\u5e8f\u9700\u8981\u5904\u7406\u7684\u4e8b\u4ef6\u3002\n\u4f8b\u5982\uff0c\u5f53\u6570\u636e\u5728\u67d0\u4e2asocket\u4e0a\u88ab\u63a5\u53d7\u540e\uff0c\u5b83\u4f1a\u8f6c\u6362\u6210\u4e00\u4e2a receive \u4e8b\u4ef6\uff0c\u7136\u540e\u88ab\u4f60\u5b9a\u4e49\u7684\u56de\u8c03\u65b9\u6cd5\u6216\u51fd\u6570\u6765\u5904\u7406\u3002\n\u4f5c\u4e3a\u4e00\u4e2a\u53ef\u80fd\u7684\u8d77\u59cb\u70b9\uff0c\u4e00\u4e2a\u4e8b\u4ef6\u9a71\u52a8\u7684\u6846\u67b6\u53ef\u80fd\u4f1a\u4ee5\u4e00\u4e2a\u5b9e\u73b0\u4e86\u4e00\u7cfb\u5217\u57fa\u672c\u4e8b\u4ef6\u5904\u7406\u5668\u65b9\u6cd5\u7684\u57fa\u7c7b\u5f00\u59cb\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class EventHandler:\n    def fileno(self):\n        'Return the associated file descriptor'\n        raise NotImplemented('must implement')\n\n    def wants_to_receive(self):\n        'Return True if receiving is allowed'\n        return False\n\n    def handle_receive(self):\n        'Perform the receive operation'\n        pass\n\n    def wants_to_send(self):\n        'Return True if sending is requested'\n        return False\n\n    def handle_send(self):\n        'Send outgoing data'\n        pass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u4e2a\u7c7b\u7684\u5b9e\u4f8b\u4f5c\u4e3a\u63d2\u4ef6\u88ab\u653e\u5165\u7c7b\u4f3c\u4e0b\u9762\u8fd9\u6837\u7684\u4e8b\u4ef6\u5faa\u73af\u4e2d\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import select\n\ndef event_loop(handlers):\n    while True:\n        wants_recv = [h for h in handlers if h.wants_to_receive()]\n        wants_send = [h for h in handlers if h.wants_to_send()]\n        can_recv, can_send, _ = select.select(wants_recv, wants_send, [])\n        for h in can_recv:\n            h.handle_receive()\n        for h in can_send:\n            h.handle_send()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e8b\u4ef6\u5faa\u73af\u7684\u5173\u952e\u90e8\u5206\u662f select() \u8c03\u7528\uff0c\u5b83\u4f1a\u4e0d\u65ad\u8f6e\u8be2\u6587\u4ef6\u63cf\u8ff0\u7b26\u4ece\u800c\u6fc0\u6d3b\u5b83\u3002\n\u5728\u8c03\u7528 select() \u4e4b\u524d\uff0c\u4e8b\u4ef6\u5faa\u73af\u4f1a\u8be2\u95ee\u6240\u6709\u7684\u5904\u7406\u5668\u6765\u51b3\u5b9a\u54ea\u4e00\u4e2a\u60f3\u63a5\u53d7\u6216\u53d1\u751f\u3002\n\u7136\u540e\u5b83\u5c06\u7ed3\u679c\u5217\u8868\u63d0\u4f9b\u7ed9 select() \u3002\u7136\u540e select() \u8fd4\u56de\u51c6\u5907\u63a5\u53d7\u6216\u53d1\u9001\u7684\u5bf9\u8c61\u7ec4\u6210\u7684\u5217\u8868\u3002\n\u7136\u540e\u76f8\u5e94\u7684 handle_receive() \u6216 handle_send() \u65b9\u6cd5\u88ab\u89e6\u53d1\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u7f16\u5199\u5e94\u7528\u7a0b\u5e8f\u7684\u65f6\u5019\uff0cEventHandler \u7684\u5b9e\u4f8b\u4f1a\u88ab\u521b\u5efa\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u662f\u4e24\u4e2a\u7b80\u5355\u7684\u57fa\u4e8eUDP\u7f51\u7edc\u670d\u52a1\u7684\u5904\u7406\u5668\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import socket\nimport time\n\nclass UDPServer(EventHandler):\n    def __init__(self, address):\n        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n        self.sock.bind(address)\n\n    def fileno(self):\n        return self.sock.fileno()\n\n    def wants_to_receive(self):\n        return True\n\nclass UDPTimeServer(UDPServer):\n    def handle_receive(self):\n        msg, addr = self.sock.recvfrom(1)\n        self.sock.sendto(time.ctime().encode('ascii'), addr)\n\nclass UDPEchoServer(UDPServer):\n    def handle_receive(self):\n        msg, addr = self.sock.recvfrom(8192)\n        self.sock.sendto(msg, addr)\n\nif __name__ == '__main__':\n    handlers = [ UDPTimeServer(('',14000)), UDPEchoServer(('',15000))  ]\n    event_loop(handlers)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u6d4b\u8bd5\u8fd9\u6bb5\u4ee3\u7801\uff0c\u8bd5\u7740\u4ece\u53e6\u5916\u4e00\u4e2aPython\u89e3\u91ca\u5668\u8fde\u63a5\u5b83\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import *\ns = socket(AF_INET, SOCK_DGRAM)\ns.sendto(b'',('localhost',14000))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.recvfrom(128)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.sendto(b'Hello',('localhost',15000))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "s.recvfrom(128)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u73b0\u4e00\u4e2aTCP\u670d\u52a1\u5668\u4f1a\u66f4\u52a0\u590d\u6742\u4e00\u70b9\uff0c\u56e0\u4e3a\u6bcf\u4e00\u4e2a\u5ba2\u6237\u7aef\u90fd\u8981\u521d\u59cb\u5316\u4e00\u4e2a\u65b0\u7684\u5904\u7406\u5668\u5bf9\u8c61\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2aTCP\u5e94\u7b54\u5ba2\u6237\u7aef\u4f8b\u5b50\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "class TCPServer(EventHandler):\n    def __init__(self, address, client_handler, handler_list):\n        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)\n        self.sock.bind(address)\n        self.sock.listen(1)\n        self.client_handler = client_handler\n        self.handler_list = handler_list\n\n    def fileno(self):\n        return self.sock.fileno()\n\n    def wants_to_receive(self):\n        return True\n\n    def handle_receive(self):\n        client, addr = self.sock.accept()\n        # Add the client to the event loop's handler list\n        self.handler_list.append(self.client_handler(client, self.handler_list))\n\nclass TCPClient(EventHandler):\n    def __init__(self, sock, handler_list):\n        self.sock = sock\n        self.handler_list = handler_list\n        self.outgoing = bytearray()\n\n    def fileno(self):\n        return self.sock.fileno()\n\n    def close(self):\n        self.sock.close()\n        # Remove myself from the event loop's handler list\n        self.handler_list.remove(self)\n\n    def wants_to_send(self):\n        return True if self.outgoing else False\n\n    def handle_send(self):\n        nsent = self.sock.send(self.outgoing)\n        self.outgoing = self.outgoing[nsent:]\n\nclass TCPEchoClient(TCPClient):\n    def wants_to_receive(self):\n        return True\n\n    def handle_receive(self):\n        data = self.sock.recv(8192)\n        if not data:\n            self.close()\n        else:\n            self.outgoing.extend(data)\n\nif __name__ == '__main__':\n   handlers = []\n   handlers.append(TCPServer(('',16000), TCPEchoClient, handlers))\n   event_loop(handlers)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "TCP\u4f8b\u5b50\u7684\u5173\u952e\u70b9\u662f\u4ece\u5904\u7406\u5668\u4e2d\u5217\u8868\u589e\u52a0\u548c\u5220\u9664\u5ba2\u6237\u7aef\u7684\u64cd\u4f5c\u3002\n\u5bf9\u6bcf\u4e00\u4e2a\u8fde\u63a5\uff0c\u4e00\u4e2a\u65b0\u7684\u5904\u7406\u5668\u88ab\u521b\u5efa\u5e76\u52a0\u5230\u5217\u8868\u4e2d\u3002\u5f53\u8fde\u63a5\u88ab\u5173\u95ed\u540e\uff0c\u6bcf\u4e2a\u5ba2\u6237\u7aef\u8d1f\u8d23\u5c06\u5176\u4ece\u5217\u8868\u4e2d\u5220\u9664\u3002\n\u5982\u679c\u4f60\u8fd0\u884c\u7a0b\u5e8f\u5e76\u8bd5\u7740\u7528Telnet\u6216\u7c7b\u4f3c\u5de5\u5177\u8fde\u63a5\uff0c\u5b83\u4f1a\u5c06\u4f60\u53d1\u9001\u7684\u6d88\u606f\u56de\u663e\u7ed9\u4f60\u3002\u5e76\u4e14\u5b83\u80fd\u5f88\u8f7b\u677e\u7684\u5904\u7406\u591a\u5ba2\u6237\u7aef\u8fde\u63a5\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b9e\u9645\u4e0a\u6240\u6709\u7684\u4e8b\u4ef6\u9a71\u52a8\u6846\u67b6\u539f\u7406\u8ddf\u4e0a\u9762\u7684\u4f8b\u5b50\u76f8\u5dee\u65e0\u51e0\u3002\u5b9e\u9645\u7684\u5b9e\u73b0\u7ec6\u8282\u548c\u8f6f\u4ef6\u67b6\u6784\u53ef\u80fd\u4e0d\u4e00\u6837\uff0c\n\u4f46\u662f\u5728\u6700\u6838\u5fc3\u7684\u90e8\u5206\uff0c\u90fd\u4f1a\u6709\u4e00\u4e2a\u8f6e\u8be2\u7684\u5faa\u73af\u6765\u68c0\u67e5\u6d3b\u52a8socket\uff0c\u5e76\u6267\u884c\u54cd\u5e94\u64cd\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e8b\u4ef6\u9a71\u52a8I/O\u7684\u4e00\u4e2a\u53ef\u80fd\u597d\u5904\u662f\u5b83\u80fd\u5904\u7406\u975e\u5e38\u5927\u7684\u5e76\u53d1\u8fde\u63a5\uff0c\u800c\u4e0d\u9700\u8981\u4f7f\u7528\u591a\u7ebf\u7a0b\u6216\u591a\u8fdb\u7a0b\u3002\n\u4e5f\u5c31\u662f\u8bf4\uff0cselect() \u8c03\u7528\uff08\u6216\u5176\u4ed6\u7b49\u6548\u7684\uff09\u80fd\u76d1\u542c\u5927\u91cf\u7684socket\u5e76\u54cd\u5e94\u5b83\u4eec\u4e2d\u4efb\u4f55\u4e00\u4e2a\u4ea7\u751f\u4e8b\u4ef6\u7684\u3002\n\u5728\u5faa\u73af\u4e2d\u4e00\u6b21\u5904\u7406\u4e00\u4e2a\u4e8b\u4ef6\uff0c\u5e76\u4e0d\u9700\u8981\u5176\u4ed6\u7684\u5e76\u53d1\u673a\u5236\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e8b\u4ef6\u9a71\u52a8I/O\u7684\u7f3a\u70b9\u662f\u6ca1\u6709\u771f\u6b63\u7684\u540c\u6b65\u673a\u5236\u3002\n\u5982\u679c\u4efb\u4f55\u4e8b\u4ef6\u5904\u7406\u5668\u65b9\u6cd5\u963b\u585e\u6216\u6267\u884c\u4e00\u4e2a\u8017\u65f6\u8ba1\u7b97\uff0c\u5b83\u4f1a\u963b\u585e\u6240\u6709\u7684\u5904\u7406\u8fdb\u7a0b\u3002\n\u8c03\u7528\u90a3\u4e9b\u5e76\u4e0d\u662f\u4e8b\u4ef6\u9a71\u52a8\u98ce\u683c\u7684\u5e93\u51fd\u6570\u4e5f\u4f1a\u6709\u95ee\u9898\uff0c\u540c\u6837\u8981\u662f\u67d0\u4e9b\u5e93\u51fd\u6570\u8c03\u7528\u4f1a\u963b\u585e\uff0c\u90a3\u4e48\u4e5f\u4f1a\u5bfc\u81f4\u6574\u4e2a\u4e8b\u4ef6\u5faa\u73af\u505c\u6b62\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5bf9\u4e8e\u963b\u585e\u6216\u8017\u65f6\u8ba1\u7b97\u7684\u95ee\u9898\u53ef\u4ee5\u901a\u8fc7\u5c06\u4e8b\u4ef6\u53d1\u9001\u4e2a\u5176\u4ed6\u5355\u72ec\u7684\u7ebf\u7a0b\u6216\u8fdb\u7a0b\u6765\u5904\u7406\u3002\n\u4e0d\u8fc7\uff0c\u5728\u4e8b\u4ef6\u5faa\u73af\u4e2d\u5f15\u5165\u591a\u7ebf\u7a0b\u548c\u591a\u8fdb\u7a0b\u662f\u6bd4\u8f83\u68d8\u624b\u7684\uff0c\n\u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u4f7f\u7528 concurrent.futures \u6a21\u5757\u6765\u5b9e\u73b0\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from concurrent.futures import ThreadPoolExecutor\nimport os\n\nclass ThreadPoolHandler(EventHandler):\n    def __init__(self, nworkers):\n        if os.name == 'posix':\n            self.signal_done_sock, self.done_sock = socket.socketpair()\n        else:\n            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n            server.bind(('127.0.0.1', 0))\n            server.listen(1)\n            self.signal_done_sock = socket.socket(socket.AF_INET,\n                                                  socket.SOCK_STREAM)\n            self.signal_done_sock.connect(server.getsockname())\n            self.done_sock, _ = server.accept()\n            server.close()\n\n        self.pending = []\n        self.pool = ThreadPoolExecutor(nworkers)\n\n    def fileno(self):\n        return self.done_sock.fileno()\n\n    # Callback that executes when the thread is done\n    def _complete(self, callback, r):\n\n        self.pending.append((callback, r.result()))\n        self.signal_done_sock.send(b'x')\n\n    # Run a function in a thread pool\n    def run(self, func, args=(), kwargs={},*,callback):\n        r = self.pool.submit(func, *args, **kwargs)\n        r.add_done_callback(lambda r: self._complete(callback, r))\n\n    def wants_to_receive(self):\n        return True\n\n    # Run callback functions of completed work\n    def handle_receive(self):\n        # Invoke all pending callback functions\n        for callback, result in self.pending:\n            callback(result)\n            self.done_sock.recv(1)\n        self.pending = []"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u4ee3\u7801\u4e2d\uff0crun() \u65b9\u6cd5\u88ab\u7528\u6765\u5c06\u5de5\u4f5c\u63d0\u4ea4\u7ed9\u56de\u8c03\u51fd\u6570\u6c60\uff0c\u5904\u7406\u5b8c\u6210\u540e\u88ab\u6fc0\u53d1\u3002\n\u5b9e\u9645\u5de5\u4f5c\u88ab\u63d0\u4ea4\u7ed9 ThreadPoolExecutor \u5b9e\u4f8b\u3002\n\u4e0d\u8fc7\u4e00\u4e2a\u96be\u70b9\u662f\u534f\u8c03\u8ba1\u7b97\u7ed3\u679c\u548c\u4e8b\u4ef6\u5faa\u73af\uff0c\u4e3a\u4e86\u89e3\u51b3\u5b83\uff0c\u6211\u4eec\u521b\u5efa\u4e86\u4e00\u5bf9socket\u5e76\u5c06\u5176\u4f5c\u4e3a\u67d0\u79cd\u4fe1\u53f7\u91cf\u673a\u5236\u6765\u4f7f\u7528\u3002\n\u5f53\u7ebf\u7a0b\u6c60\u5b8c\u6210\u5de5\u4f5c\u540e\uff0c\u5b83\u4f1a\u6267\u884c\u7c7b\u4e2d\u7684 _complete() \u65b9\u6cd5\u3002\n\u8fd9\u4e2a\u65b9\u6cd5\u518d\u67d0\u4e2asocket\u4e0a\u5199\u5165\u5b57\u8282\u4e4b\u524d\u4f1a\u8bb2\u6302\u8d77\u7684\u56de\u8c03\u51fd\u6570\u548c\u7ed3\u679c\u653e\u5165\u961f\u5217\u4e2d\u3002\nfileno() \u65b9\u6cd5\u8fd4\u56de\u53e6\u5916\u7684\u90a3\u4e2asocket\u3002\n\u56e0\u6b64\uff0c\u8fd9\u4e2a\u5b57\u8282\u88ab\u5199\u5165\u65f6\uff0c\u5b83\u4f1a\u901a\u77e5\u4e8b\u4ef6\u5faa\u73af\uff0c\n\u7136\u540e handle_receive() \u65b9\u6cd5\u88ab\u6fc0\u6d3b\u5e76\u4e3a\u6240\u6709\u4e4b\u524d\u63d0\u4ea4\u7684\u5de5\u4f5c\u6267\u884c\u56de\u8c03\u51fd\u6570\u3002\n\u5766\u767d\u8bb2\uff0c\u8bf4\u4e86\u8fd9\u4e48\u591a\u8fde\u6211\u81ea\u5df1\u90fd\u6655\u4e86\u3002\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u670d\u52a1\u5668\uff0c\u6f14\u793a\u4e86\u5982\u4f55\u4f7f\u7528\u7ebf\u7a0b\u6c60\u6765\u5b9e\u73b0\u8017\u65f6\u7684\u8ba1\u7b97\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# A really bad Fibonacci implementation\ndef fib(n):\n    if n < 2:\n        return 1\n    else:\n        return fib(n - 1) + fib(n - 2)\n\nclass UDPFibServer(UDPServer):\n    def handle_receive(self):\n        msg, addr = self.sock.recvfrom(128)\n        n = int(msg)\n        pool.run(fib, (n,), callback=lambda r: self.respond(r, addr))\n\n    def respond(self, result, addr):\n        self.sock.sendto(str(result).encode('ascii'), addr)\n\nif __name__ == '__main__':\n    pool = ThreadPoolHandler(16)\n    handlers = [ pool, UDPFibServer(('',16000))]\n    event_loop(handlers)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd0\u884c\u8fd9\u4e2a\u670d\u52a1\u5668\uff0c\u7136\u540e\u8bd5\u7740\u7528\u5176\u5b83Python\u7a0b\u5e8f\u6765\u6d4b\u8bd5\u5b83\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import *\nsock = socket(AF_INET, SOCK_DGRAM)\nfor x in range(40):\n    sock.sendto(str(x).encode('ascii'), ('localhost', 16000))\n    resp = sock.recvfrom(8192)\n    print(resp[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u5e94\u8be5\u80fd\u5728\u4e0d\u540c\u7a97\u53e3\u4e2d\u91cd\u590d\u7684\u6267\u884c\u8fd9\u4e2a\u7a0b\u5e8f\uff0c\u5e76\u4e14\u4e0d\u4f1a\u5f71\u54cd\u5230\u5176\u4ed6\u7a0b\u5e8f\uff0c\u5c3d\u7ba1\u5f53\u6570\u5b57\u4fbf\u8d8a\u6765\u8d8a\u5927\u65f6\u5019\u5b83\u4f1a\u53d8\u5f97\u8d8a\u6765\u8d8a\u6162\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5df2\u7ecf\u9605\u8bfb\u5b8c\u4e86\u8fd9\u4e00\u5c0f\u8282\uff0c\u90a3\u4e48\u4f60\u5e94\u8be5\u4f7f\u7528\u8fd9\u91cc\u7684\u4ee3\u7801\u5417\uff1f\u4e5f\u8bb8\u4e0d\u4f1a\u3002\u4f60\u5e94\u8be5\u9009\u62e9\u4e00\u4e2a\u53ef\u4ee5\u5b8c\u6210\u540c\u6837\u4efb\u52a1\u7684\u9ad8\u7ea7\u6846\u67b6\u3002\n\u4e0d\u8fc7\uff0c\u5982\u679c\u4f60\u7406\u89e3\u4e86\u57fa\u672c\u539f\u7406\uff0c\u4f60\u5c31\u80fd\u7406\u89e3\u8fd9\u4e9b\u6846\u67b6\u6240\u4f7f\u7528\u7684\u6838\u5fc3\u6280\u672f\u3002\n\u4f5c\u4e3a\u5bf9\u56de\u8c03\u51fd\u6570\u7f16\u7a0b\u7684\u66ff\u4ee3\uff0c\u4e8b\u4ef6\u9a71\u52a8\u7f16\u7801\u6709\u65f6\u5019\u4f1a\u4f7f\u7528\u5230\u534f\u7a0b\uff0c\u53c2\u800312.12\u5c0f\u8282\u7684\u4e00\u4e2a\u4f8b\u5b50\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 11.13 \u53d1\u9001\u4e0e\u63a5\u6536\u5927\u578b\u6570\u7ec4\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u95ee\u9898\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4f60\u8981\u901a\u8fc7\u7f51\u7edc\u8fde\u63a5\u53d1\u9001\u548c\u63a5\u53d7\u8fde\u7eed\u6570\u636e\u7684\u5927\u578b\u6570\u7ec4\uff0c\u5e76\u5c3d\u91cf\u51cf\u5c11\u6570\u636e\u7684\u590d\u5236\u64cd\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u89e3\u51b3\u65b9\u6848\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e0b\u9762\u7684\u51fd\u6570\u5229\u7528 memoryviews \u6765\u53d1\u9001\u548c\u63a5\u53d7\u5927\u6570\u7ec4\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# zerocopy.py\n\ndef send_from(arr, dest):\n    view = memoryview(arr).cast('B')\n    while len(view):\n        nsent = dest.send(view)\n        view = view[nsent:]\n\ndef recv_into(arr, source):\n    view = memoryview(arr).cast('B')\n    while len(view):\n        nrecv = source.recv_into(view)\n        view = view[nrecv:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e3a\u4e86\u6d4b\u8bd5\u7a0b\u5e8f\uff0c\u9996\u5148\u521b\u5efa\u4e00\u4e2a\u901a\u8fc7socket\u8fde\u63a5\u7684\u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\u7a0b\u5e8f\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import *\ns = socket(AF_INET, SOCK_STREAM)\ns.bind(('', 25000))\ns.listen(1)\nc,a = s.accept()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u5ba2\u6237\u7aef\uff08\u53e6\u5916\u4e00\u4e2a\u89e3\u91ca\u5668\u4e2d\uff09\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from socket import *\nc = socket(AF_INET, SOCK_STREAM)\nc.connect(('localhost', 25000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u672c\u8282\u7684\u76ee\u6807\u662f\u4f60\u80fd\u901a\u8fc7\u8fde\u63a5\u4f20\u8f93\u4e00\u4e2a\u8d85\u5927\u6570\u7ec4\u3002\u8fd9\u79cd\u60c5\u51b5\u7684\u8bdd\uff0c\u53ef\u4ee5\u901a\u8fc7 array \u6a21\u5757\u6216 numpy \u6a21\u5757\u6765\u521b\u5efa\u6570\u7ec4\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy\na = numpy.arange(0.0, 50000000.0)\nsend_from(a, c)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy\na = numpy.zeros(shape=50000000, dtype=float)\na[0:10]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "recv_into(a, c)\na[0:10]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### \u8ba8\u8bba\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5728\u6570\u636e\u5bc6\u96c6\u578b\u5206\u5e03\u5f0f\u8ba1\u7b97\u548c\u5e73\u884c\u8ba1\u7b97\u7a0b\u5e8f\u4e2d\uff0c\u81ea\u5df1\u5199\u7a0b\u5e8f\u6765\u5b9e\u73b0\u53d1\u9001/\u63a5\u53d7\u5927\u91cf\u6570\u636e\u5e76\u4e0d\u5e38\u89c1\u3002\n\u4e0d\u8fc7\uff0c\u8981\u662f\u4f60\u786e\u5b9e\u60f3\u8fd9\u6837\u505a\uff0c\u4f60\u53ef\u80fd\u9700\u8981\u5c06\u4f60\u7684\u6570\u636e\u8f6c\u6362\u6210\u539f\u59cb\u5b57\u8282\uff0c\u4ee5\u4fbf\u7ed9\u4f4e\u5c42\u7684\u7f51\u7edc\u51fd\u6570\u4f7f\u7528\u3002\n\u4f60\u53ef\u80fd\u8fd8\u9700\u8981\u5c06\u6570\u636e\u5207\u5272\u6210\u591a\u4e2a\u5757\uff0c\u56e0\u4e3a\u5927\u90e8\u5206\u548c\u7f51\u7edc\u76f8\u5173\u7684\u51fd\u6570\u5e76\u4e0d\u80fd\u4e00\u6b21\u6027\u53d1\u9001\u6216\u63a5\u53d7\u8d85\u5927\u6570\u636e\u5757\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528\u67d0\u79cd\u673a\u5236\u5e8f\u5217\u5316\u6570\u636e\u2014\u2014\u53ef\u80fd\u5c06\u5176\u8f6c\u6362\u6210\u4e00\u4e2a\u5b57\u8282\u5b57\u7b26\u4e32\u3002\n\u4e0d\u8fc7\uff0c\u8fd9\u6837\u6700\u7ec8\u4f1a\u521b\u5efa\u6570\u636e\u7684\u4e00\u4e2a\u590d\u5236\u3002\n\u5c31\u7b97\u4f60\u53ea\u662f\u96f6\u788e\u7684\u505a\u8fd9\u4e9b\uff0c\u4f60\u7684\u4ee3\u7801\u6700\u7ec8\u8fd8\u662f\u4f1a\u6709\u5927\u91cf\u7684\u5c0f\u578b\u590d\u5236\u64cd\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u672c\u8282\u901a\u8fc7\u4f7f\u7528\u5185\u5b58\u89c6\u56fe\u5c55\u793a\u4e86\u4e00\u4e9b\u9b54\u6cd5\u64cd\u4f5c\u3002\n\u672c\u8d28\u4e0a\uff0c\u4e00\u4e2a\u5185\u5b58\u89c6\u56fe\u5c31\u662f\u4e00\u4e2a\u5df2\u5b58\u5728\u6570\u7ec4\u7684\u8986\u76d6\u5c42\u3002\u4e0d\u4ec5\u4ec5\u662f\u90a3\u6837\uff0c\n\u5185\u5b58\u89c6\u56fe\u8fd8\u80fd\u4ee5\u4e0d\u540c\u7684\u65b9\u5f0f\u8f6c\u6362\u6210\u4e0d\u540c\u7c7b\u578b\u6765\u8868\u73b0\u6570\u636e\u3002\n\u8fd9\u4e2a\u5c31\u662f\u4e0b\u9762\u8fd9\u4e2a\u8bed\u53e5\u7684\u76ee\u7684\uff1a"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "view = memoryview(arr).cast('B')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5b83\u63a5\u53d7\u4e00\u4e2a\u6570\u7ec4 arr\u5e76\u5c06\u5176\u8f6c\u6362\u4e3a\u4e00\u4e2a\u65e0\u7b26\u53f7\u5b57\u8282\u7684\u5185\u5b58\u89c6\u56fe\u3002\u8fd9\u4e2a\u89c6\u56fe\u80fd\u88ab\u4f20\u9012\u7ed9socket\u76f8\u5173\u51fd\u6570\uff0c\n\u6bd4\u5982 socket.send() \u6216 send.recv_into() \u3002\n\u5728\u5185\u90e8\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u80fd\u591f\u76f4\u63a5\u64cd\u4f5c\u8fd9\u4e2a\u5185\u5b58\u533a\u57df\u3002\u4f8b\u5982\uff0csock.send() \u76f4\u63a5\u4ece\u5185\u5b58\u4e2d\u53d1\u751f\u6570\u636e\u800c\u4e0d\u9700\u8981\u590d\u5236\u3002\nsend.recv_into() \u4f7f\u7528\u8fd9\u4e2a\u5185\u5b58\u533a\u57df\u4f5c\u4e3a\u63a5\u53d7\u64cd\u4f5c\u7684\u8f93\u5165\u7f13\u51b2\u533a\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u5269\u4e0b\u7684\u4e00\u4e2a\u96be\u70b9\u5c31\u662fsocket\u51fd\u6570\u53ef\u80fd\u53ea\u64cd\u4f5c\u90e8\u5206\u6570\u636e\u3002\n\u901a\u5e38\u6765\u8bb2\uff0c\u6211\u4eec\u5f97\u4f7f\u7528\u5f88\u591a\u4e0d\u540c\u7684 send() \u548c recv_into() \u6765\u4f20\u8f93\u6574\u4e2a\u6570\u7ec4\u3002\n\u4e0d\u7528\u62c5\u5fc3\uff0c\u6bcf\u6b21\u64cd\u4f5c\u540e\uff0c\u89c6\u56fe\u4f1a\u901a\u8fc7\u53d1\u9001\u6216\u63a5\u53d7\u5b57\u8282\u6570\u91cf\u88ab\u5207\u5272\u6210\u65b0\u7684\u89c6\u56fe\u3002\n\u65b0\u7684\u89c6\u56fe\u540c\u6837\u4e5f\u662f\u5185\u5b58\u8986\u76d6\u5c42\u3002\u56e0\u6b64\uff0c\u8fd8\u662f\u6ca1\u6709\u4efb\u4f55\u7684\u590d\u5236\u64cd\u4f5c\u3002"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\u8fd9\u91cc\u6709\u4e2a\u95ee\u9898\u5c31\u662f\u63a5\u53d7\u8005\u5fc5\u987b\u4e8b\u5148\u77e5\u9053\u6709\u591a\u5c11\u6570\u636e\u8981\u88ab\u53d1\u9001\uff0c\n\u4ee5\u4fbf\u5b83\u80fd\u9884\u5206\u914d\u4e00\u4e2a\u6570\u7ec4\u6216\u8005\u786e\u4fdd\u5b83\u80fd\u5c06\u63a5\u53d7\u7684\u6570\u636e\u653e\u5165\u4e00\u4e2a\u5df2\u7ecf\u5b58\u5728\u7684\u6570\u7ec4\u4e2d\u3002\n\u5982\u679c\u6ca1\u529e\u6cd5\u77e5\u9053\u7684\u8bdd\uff0c\u53d1\u9001\u8005\u5c31\u5f97\u5148\u5c06\u6570\u636e\u5927\u5c0f\u53d1\u9001\u8fc7\u6765\uff0c\u7136\u540e\u518d\u53d1\u9001\u5b9e\u9645\u7684\u6570\u7ec4\u6570\u636e\u3002"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.1"
    },
    "toc": {
      "base_numbering": 1,
      "nav_menu": {},
      "number_sections": true,
      "sideBar": true,
      "skip_h1_title": true,
      "title_cell": "Table of Contents",
      "title_sidebar": "Contents",
      "toc_cell": false,
      "toc_position": {},
      "toc_section_display": true,
      "toc_window_display": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}